Generate and format dates with Moment in Nodejs

Asked

Viewed 2,000 times

3

I’m trying to use the Moment for formatting dates this way YYYY-MM-DD HH:mm:ss and would like to determine a period between 00:00:00 yesterday and 23:59:59 today. Example: considering today as 25/07/2017, would be:

dateFrom: 2017-07-24 00:00:00
dateTo:  2017-07-25 23:59:59

How I set these dates with Moment and force formatting on YYYY-MM-DD HH:mm:ss?

2 answers

1

Considering a variable "data1" which is an object of type Date is already with the correct date in question, which in this case is 25/07/2017, just do the following:

// data1 já é um objeto do tipo "Date"
var dt = moment(data1);
// 
console.log(dt.format('YYYY-MM-DD 00:00:00'));
console.log(dt.format('YYYY-MM-DD 23:59:59'));

// Se "data1" também tiver algum valor de hora setado que quisermos saber
console.log(dt.format('YYYY-MM-DD HH:mm:ss'));

1

These times (midnight and 23:59:59) represent respectively the beginning and end of the day, so just use the functions startOf and endOf, that make the appropriate adjustments for these times, simply pass as parameter the string 'day':

let d = moment(); // data atual

// startOf seta o horário para meia-noite e endOf, para 23:59:59
// mas se hoje for o dia em que começa o horário de verão no Brasil, startOf pode
// setar para 01:00 (veja explicação mais abaixo)
console.log(d.startOf('day').format('YYYY-MM-DD HH:mm:ss'));
console.log(d.endOf('day').format('YYYY-MM-DD HH:mm:ss'));
<script src="https://momentjs.com/downloads/moment.min.js"></script>

Thus, the date has changed to the beginning of the day (00:00:00) and the end of the day (23:59:59).

"Force" hourly values to 00:00:00 or 23:59:59 (as done at another answer) also shows the same result, but there are some details to be attentive.

The first is that a Date of Javascript (which is the object encapsulated by a Moment) actually represents a timestamp (the quantity of milliseconds Unix Epoch) and at all times will have some set time value. In fact, the timestamp represents a single instant - a point in the timeline - and corresponds to a different date and time, depending on the time zone. But the point is that there is always a value for the time fields, and ignoring or artificially overwriting them is not the ideal solution.


Another point is that startOf and endOf always adjust the values according to the browser Timezone (time zone). My browser, for example, is using the Timezone corresponding to the Time of Brasilia, and this can have problems when the daylight saving time begins. Ex:

// 4 de novembro de 2018 (lembrando que janeiro é zero, fevereiro é 1, etc)
let d = moment([2018, 10, 4]);

// 2018-11-04 01:00:00 (se o browser usar o fuso do Horário de Brasília)
console.log(d.startOf('day').format('YYYY-MM-DD HH:mm:ss'));
<script src="https://momentjs.com/downloads/moment.min.js"></script>

I used the date of November 4, 2018 (remembering that in Javascript the months start at zero: January is zero, February is 1, etc). In the Timezone corresponding to the Time of Brasilia, this is the day the daylight saving time began: at midnight on the 4th the clocks were automatically advanced to 1 am. This means that, in fact, the clocks jumped from 23:59 of day 3 straight to 01:00 of day 4. Ie, the beginning of day 04/11/2018, in this Timezone, was 1 in the morning (and not midnight).

Therefore, if you test the above code in a browser that follows the Brasilia Time (generally the browser uses the OS configuration, check yours before testing), the above code will print 2018-11-04 01:00:00. If you are using any other Timezone (in which there is no daylight saving time this day), the result will be 2018-11-04 00:00:00.

Therefore, if you use the solution of always putting the fixed value 00:00:00, can end up with a problem in summer time transitions. Some may argue that putting 00:00:00 fixed can "fix" this problem, but in fact the summer time rule determines that midnight does not exist on that day, in that time zone. Then it is better to show the time when the day actually starts, instead of showing an invalid time in the Timezone where the user is located.


For the end of the day, it is also not guaranteed to always be 23:59:59. For example, in Bangladesh, on 19 June 2019 Daylight saving time began at 23:00, so the clocks were brought forward from 22:59:29 directly to midnight on the 20th. That means the end of the 19th was not at 23:59:59, but at 22:59:59.

Changing the operating system time zone setting to "Dhaka, Bangladesh", the code below prints "2009-06-19 22:59:59":

// 19 de junho de 2009
let d = moment([2009, 5, 19]);

// 2009-06-19 22:59:59 <- caso o fuso horário esteja configurado para Dhaka, Bangladesh
console.log(d.endOf('day').format('YYYY-MM-DD HH:mm:ss'));
<script src="https://momentjs.com/downloads/moment.min.js"></script>
<script src="https://momentjs.com/downloads/moment-timezone-with-data.min.js"></script>

Forcing "23:59:59", you will be printing a time that does not exist on that day, on that Timezone.

"Ah, but that was in 2009 in a distant country, where I live that doesn’t happen!"

Currently it may not even happen, but the rules of time zones change all the time. In Brazil summer time has changed several times over time: there was a change in 2018, for example, when the beginning ceased to be in October and became in November (and already changed again, Brazil will not have daylight saving time in 2019, and will be so "forever" - that is, until it changes again). At this time the European Union is on its way to eliminating daylight saving time. And at any time some government is thinking of changing the rules of the time zone its country, state, province, city or whatever.

Therefore, nothing guarantees that this cannot happen on "our" Timezone. Since you’re using a library that takes care of those details, you better leave it up to your respective functions, instead of putting fixed values that "work" - it might even work in most cases, but since Moment.js also works for these cases and still handles the more complicated exceptions, why not let him handle it? Use startOf and endOf is much more guaranteed than putting "00:00:00" and "23:59:59" directly in the code.


Moment Timezone

Another option, if you want to always show 00:00:00, independent of Timezone, is to use the Moment Timezone and force a specific Timezone. To not suffer summer time effects, for example, you can force everything to UTC:

// 4 de novembro de 2018 (lembrando que janeiro é zero, fevereiro é 1, etc)
let d = moment.tz([2018, 10, 4], "UTC");

// 2018-11-04 00:00:00
console.log(d.startOf('day').format('YYYY-MM-DD HH:mm:ss'));
<script src="https://momentjs.com/downloads/moment.min.js"></script>
<script src="https://momentjs.com/downloads/moment-timezone-with-data.min.js"></script>

Using UTC, the summer time effects no longer exist, and now the code always prints 2018-11-04 00:00:00, independent of the Timezone system.

Just remembering that midnight on UTC it won’t necessarily be midnight in the browser time zone the user is using.

For example, midnight at UTC corresponds to 9 of the night of the previous day in the Schedule of Brasilia (or 10 of the night when it is in daylight hours). The same goes for 23:59:59 (in UTC may not be the same time in the browser’s Timezone).

Take this into account when showing these times to the user.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.