this post was submitted on 06 Nov 2023
29 points (68.4% liked)

Programmer Humor

32000 readers
1744 users here now

Post funny things about programming here! (Or just rant about your favourite programming language.)

Rules:

founded 5 years ago
MODERATORS
top 49 comments
sorted by: hot top controversial new old
[–] [email protected] 41 points 10 months ago (1 children)

You want to create the date "31st February", but it's JavaScript that's cursed?

Write a less side-effecty function.

function getMonthName(monthNumber) {
    const date = new Date(2023, monthNumber - 1, 1);
    return date.toLocaleString([], { month: 'long' });
}
[–] [email protected] 0 points 10 months ago* (last edited 10 months ago) (1 children)

The point is that this scenario exists in Js in the first place. It's a completely unnecessary rake left around for people to step on. Also, the function isn't side effecty since it doesn't make implicit references outside its scope. The fact that the date is mutable is an internal concern there. You could just as easily do

function getMonthName(monthNumber) {
  const date = new Date();
  date.setDate(1);  
  date.setMonth(monthNumber - 1);

  return date.toLocaleString([], { month: 'long' });
}

The problem here isn't with side effects, but with having to know that you want to set your date to first day to get the next month reliably.

[–] [email protected] 14 points 10 months ago* (last edited 10 months ago) (1 children)

The rake has nothing to do with JS (which I agree is cursed, but for its own reasons, not this).

You have called a function in a way that does not give a consistent value (Date()). Such functions are hardly the preserve of JavaScript. You've failed to adequately deal with the range of values produced, with code that tries to insist that the "31st February" can be a meaningful date in February. You should accept that this is your mistake and learn to (better) avoid side effects where possible.

Also, the function isn't side effecty since it doesn't make implicit references outside its scope.

Edit responding to your edit:

Also, the function isn't side effecty since it doesn't make implicit references outside its scope.

The Date() function's output varies according to something other than its input (and even the rest of your program). Using its output without accounting for that variation means that your function, as originally written, also gives inconsistent return values, varying according to something other than its input, because it does, in fact, reference something outside the function. If it did not, the results would only depend on the monthNumber argument, and would always be consistent. I don't know what you call that, but I view it as a side effect.

As you have said, the rake is that months have different lengths, and you need to account for that. But that's not one of JavaScript's many issues.

[–] [email protected] -5 points 10 months ago (1 children)

The idea is to get the current data that will have the current year, month, day in it, and then to query this date for the previous month. A sane API would just throw an error when the date is out of range. A Js API will quitely give you nonsense instead. Again, side effects have absolutely nothing to do with anything here.

[–] [email protected] 6 points 10 months ago (1 children)

You've replied while I was editing, so see that regarding what I mean by side effects.

As far as throwing an error when you try to create "31st February", this wouldn't actually help much, since the error would still only occur on some days of the year, because your original code doesn't account for the range of outputs from Date() when called without arguments.

To perform correctly, your code needs to normalise the day of the month, or just create the date more explicitly to begin with, but this is a calendrical issue, not a JavaScript one.

[–] [email protected] 20 points 10 months ago

The legacy Date object has many problems and this is one of them. Another infamous one is that it uses zero-based month numbers: January is the zeroth month and December the 11th month.

This will be fixed Any Day Now™️ when Temporal is released. This is a carefully designed library that supersedes Date and is currently waiting on some standards to be finalized.

[–] [email protected] 9 points 10 months ago* (last edited 10 months ago) (1 children)

date.setDate(1);

Problem solved.

[–] [email protected] -1 points 10 months ago (2 children)

Sure, but the question is why anybody thought this would be a desirable behavior in the first place.

[–] [email protected] 17 points 10 months ago (1 children)

It's because there's no right answer, and this way gets you the intuitive answer most often.

A month isn't a proper unit of time. Adding a month to a date can't be done without specifying which month you're adding.

You could argue that one month from January 31 is February 28, 29 (depending on the year), March 2, or 3.

Should one month from the last day be the last day of the next month? That would mean that the 30th and the 31st of march are both the same duration from April 30th, and a month before April 30th could logically map to either one.

So they chose the path that, for anything other than the 31st, and the 29th and 30th if it comes near February, works as you expect. "A month after 17 days from the first of January is 17 days after the first of february.”

The other alternatives involve not allowing the addition and subtraction of irregular time intervals, but then you get frustrated that you can only deal with seconds, since those don't change in length.

[–] [email protected] 4 points 10 months ago (2 children)

I love js. But the date object has always been a total pain. Moment.js is a good package to deal with it, but yeah, it's currently deprecated, but it would be nice if it or something like it became part of ECMAScript.

I have no idea why it hasn't yet, except that it might be that js needs to work for everyone, not just the us. So time is not standard.

[–] [email protected] 3 points 10 months ago* (last edited 10 months ago) (1 children)

The date API is like the original rip of the Java date API. Barely changed, and totally backwards compatible nonsense.

Temporal is the new JavaScript/ECMAScript date API.
It's stage 3, and likely stable (just a few kinks being worked out). So you could polyfill it for production.
https://github.com/tc39/proposal-temporal

[–] [email protected] 2 points 10 months ago

Speaking of Java RipS. How annoying is it the JS has left Java in the dust as far as looser standards?

Developing in Java: YOU FORGOT A SEMI-COLON ARE YOU CRAZY?! HOW IS THE COMPILER SUPPOSED TO KNOW WHAT TO DO?!

Developing in JS: Who gives a fuck about semi-colons?

[–] [email protected] 2 points 10 months ago

You may be interested in the datefns library if you need a replacement for momentjs.

[–] [email protected] 7 points 10 months ago

Oh, because if the month you chose has less than 31 days, it'll assume the 31st of September is the 1st of October? That's reasonable.

[–] [email protected] 3 points 10 months ago (2 children)

The amount of people arguing that this is a fine behavior in this thread makes the whole thing even funnier.

[–] [email protected] 3 points 10 months ago (2 children)

What would you expect "-1 month" to do for a date like 31st of March? Would the result be the same as for "-1 month" on 29th of March?

If you go back 2 months so the 31st is existing again - should that mean that the result of using -1 month twice should be different to using -2 months?

I think it's just a stupid way to implement something like this as "month" isn't a defined size so defining it with a fixed value and documenting it properly is a decent solution but noone should use that kind of function in the first place

[–] [email protected] 4 points 10 months ago* (last edited 10 months ago)

It is a stupid way to implement it, but the called function is named setMonth()! The minus one is performed externally, so if you set February you expect February, validation should adjust the other fields...

[–] [email protected] 3 points 10 months ago

This is literally how every sane API works in languages built by adults. For example, here's what happens in Java:

java.time.LocalDate.of(2023, 3, 31)
> #object[java.time.LocalDate 0x2bc77260 "2023-03-31"]
java.time.LocalDate.of(2023, 3, 31).minusMonths(1)
> #object[java.time.LocalDate 0xac0dc15 "2023-02-28"]
java.time.LocalDate.of(2023, 3, 31).minusMonths(2)
> #object[java.time.LocalDate 0x44b9305f "2023-01-31"]

I have no idea where people get this notion that a month isn't a defined size. Do people just not understand the concept of a month?

[–] [email protected] 1 points 10 months ago (1 children)

I would expect the month to increment by one and the day to be clamped to the valid days for the month.

[–] [email protected] -3 points 10 months ago

That's precisely what I'd expect as well, and what APIs in languages like Java do.

[–] [email protected] 3 points 10 months ago (1 children)

Somebody has not worked with dates for very long, to be so sure of themselves...

[–] [email protected] -5 points 10 months ago

I've worked with dates long enough in lots of different languages to recognize API decisions that are absurd.