Get the date before an informed one

Asked

Viewed 602 times

1

var date = '2019-01-01';
var d = new Date( date );
d.setDate( d.getDate() );

document.write(d);

Returned that:

Mon Dec 31 2018 22:00:00 GMT-0200 (Brasilia daylight saving time)

How do I now return like this:

2018/12/31

Javascript or jQuery?

  • 1

    suggest using the Moment.js who does it in a very simple way, for example moment().format("yyyy/MM/dd");

  • I think you can find here what you’re looking for... https://answall.com/q/205086/129

  • using a library just once wouldn’t like it. It’s easier to make a explode and then mount the string. But I would like to know how to receive in American format

  • d.setDate( d.getDate() ) is redundant and unnecessary because you are setting the same value as the field already has (i.e., it is not changing anything): https://jsfiddle.net/y3ms2qu1/

  • @Ricardopunctual In fact it is moment().format("YYYY/MM/DD") (with the Y and D uppercase): https://jsfiddle.net/372uzpmg/1/

  • 1

    Cool, well noted @hkotsubo

Show 1 more comment

2 answers

2


Heed, your code looks like be picking up the date of the previous day, but it was just luck/coincidence. Let’s understand what actually happens.


Builder of Date

When you pass a string to the builder of Date, it behaves in the same way as the method Date.parse. This, in turn, when the string has only the date, interprets it as UTC. In addition, the time is set to midnight, ie the code below:

let d = new Date('2019-01-01');

Produces a date equivalent to 1 January 2019 at midnight, in UTC.

The detail is that when printing the date (be with console.log, document.write, alert or whatever), it is shown in the browser’s Timezone (which in turn uses what is configured in the operating system).

In your case - and in mine too - the browser is using the Brasilia time, and so the output was:

Mon Dec 31 2018 22:00:00 GMT-0200 (Brasilia Summer Time)

In his case it was "Brasilia Summer Time" instead of "Brasilia Summer Time", because the language of his browser is set to Portuguese, and mine is in English. But what matters is that the Timezone used was the official schedule of Brasilia.

This happens because "1 January 2019 at midnight in UTC" is equal to "31 December 2018 at 22h in Brasilia time". The instant is the same, but in different parts of the world the date and time may be different.

You can observe this if you check the value of getTime(), that returns the value of timestamp:

let d = new Date('2019-01-01');
console.log(d.getTime()); // 1546300800000

The return is 1546300800000, which is the amount of milliseconds since the Unix Epoch (01/01/1970 at midnight in UTC). This value represents a single instant that is the same worldwide.

The detail is that this same value may correspond to a different date and time, depending on the time zone you are in. In São Paulo, this timestamp corresponds to 31/12/2018 at 22h, but in Tokyo, that same timestamp corresponds to 01/01/2019 at 9 am.

Using the date in question, you can simulate this behavior by simply changing your computer’s time zone settings and testing. When I switched to Japan time zone, when printing d the result was:

Tue Jan 01 2019 09:00:00 GMT+0900 (Japan Standard Time)

But when changing the time zone back to Brazil, the result was:

Mon Dec 31 2018 22:00:00 GMT-0200 (Brasilia Summer Time)

All without even changing the value of d (just printing again). It may be that, depending on the system, you need to restart the browser to get the new time zone, but in my case it was not necessary.

This same behavior occurs with toLocaleDateString, that returns the values of the day, month and year according to the browser Timezone. Again, changing the Timezone of my computer to that of Japan, d.toLocaleDateString('pt-BR') returns:

01/01/2019

Returning to the Timezone configuration for Brazil time, the return is:

31/12/2018

And once again, without changing the value of d. Note that the parameter 'pt-BR' serves only to define the date format (in case, day, month and year separated by /), but the values of the day, month and year depend on the Timezone configured.

And the same behavior occurs for getters (as getDate(), getMonth(), getHours(), etc). So your code is extremely dependent on the environment in which it will run. In some cases, "it will work", in others it won’t. It might seem a silly mistake and "obviously it won’t happen to me, my clients are all from Brazil", But depending so much on each customer’s local settings to get the right result doesn’t seem like a good approach. Especially when there are ways to resolve.


So how to solve?

Since the date is generated in UTC, use the methods getUTCxxx, that return the value of the day, month and year in UTC (ie, their values do not depend on the browser Timezone).

And how the Date generated has the set time for midnight in UTC, just subtract 1 from the value of getTime(), that the resulting date will be the day before 23:59:59.999 - and as I am only interested in the day, month and year, this is enough.

Then I use the methods getUTCxxx (to get the date values in UTC, so do not depend on the browser Timezone), and use padStart to complete values less than 10 with a zero on the left (to write day 1 as 01, for example).

Another annoying detail is that getUTCMonth() returns values between 0 and 11 (January is zero, February is 1, etc.), so we have to remember to add 1 (this Javascript date API it’s terrible).

let d = new Date('2019-01-01');
d.setTime(d.getTime() - 1);
console.log(d.getUTCFullYear() + '/' +
            (d.getUTCMonth() + 1).toString().padStart(2, '0') + '/' +
            d.getUTCDate().toString().padStart(2, '0')); // 2018/12/31

With this, the result will always be 2018/12/31, independent of the browser Timezone, since we are working with the values in UTC.

If you want to be precise and subtract exactly 1 day, do it d.setTime(d.getTime() - (1000 * 3600 * 24)) (this subtracts the amount of milliseconds in a day, the result will be midnight of the previous day in UTC). As we are working with date values in UTC, there are no problems with daylight saving time, and the result will always be the day before it was passed in the Date.


If you want, you can also use your solution with toLocaleDateString. The only detail is that you can pass as parameter the Timezone, then I can pass "UTC" and so not depend on the browser Timezone.

If you do not specify the Timezone, the browser will be used, which as we have seen, is not a reliable value for your case.

let d = new Date('2019-01-01');
d.setTime(d.getTime() - 1);
let partes = d.toLocaleDateString('pt-BR', { timeZone: 'UTC' }).split("/");
let dia = partes[0];
let mes = partes[1];
let ano = partes[2];
console.log(ano + "/" + mes + "/" + dia); // 2018/12/31

In the most modern browsers (ES6 compliant) I can do that too:

let d = new Date('2019-01-01');
d.setTime(d.getTime() - 1);
let [dia, mes, ano] = d.toLocaleDateString('pt-BR', { timeZone: 'UTC' }).split("/");
console.log(`${ano}/${mes}/${dia}`); // 2018/12/31


Moment js.

In the comments you said that does not want to use a library. But the question says that the solution can use jQuery if it is the case. Well, seeing the respective websites today, the js file from Moment js. is roughly half the size of jQuery. If you are already using jQuery (which nowadays, depending on the case, maybe not so necessary), why not use a library - by the way, excellent - to deal specifically with dates, since the native API it’s so bad?

Of course, using a library just for a specific snippet may seem like overkill, but if you’re going to manipulate dates at more points in the code, it might be worth it. At your discretion.

Anyway, personal preferences and project decisions aside, I leave below a solution with Moment.js. The advantage is that the date is interpreted in the browser Timezone, so I can manipulate it without fear of having implicit conversions from/to UTC.

First I use the constructor that receives the string and its format. Then use subtract to obtain the day before, and finally use format to return in the desired format:

let d = moment('2019-01-01', 'YYYY-MM-DD');
d.subtract(1, 'day');
console.log(d.format('YYYY/MM/DD')); // 2018/12/31
<script src="https://momentjs.com/downloads/moment.min.js"></script>


Notice I used let instead of var to declare variables. If curious, see this question to know the difference between them.

  • 1

    I thought the class was fantastic and I couldn’t help but accept your answer. But I thought I’d bring the dates straight from the bank and I’ll study this exhibition of yours more. Thank you!

0

var date = '2019-01-01';
var d = new Date( date );
d.setDate( d.getDate() );

splite = d.toLocaleDateString('pt-BR').split("/");

dia =splite[0];
mes =splite[1];
ano =splite[2];

data = ano + "/" + mes + "/" + dia; 
document.write(data);

Browser other questions tagged

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