I need to compare two dates in my code and to make sure I don't make any mistakes with time zones, I need to handle this comparison in UTC.
My code looks like this:
const date1String = "7/15/2017 15:00"; // I get this from backend API. To keep it simple, I showed it as a declaration.
const date1 = new Date(date1String).toISOString();
const dateToTest = new Date(2017, 7, 21, 10, 0).toISOString();
if(date1 < dateToTest) {
// Some logic here
}
The date1String is a value I receive from my backend API which comes in string format but is always in UTC so I'm trying to convert it to a JavaScript date while keeping it in UTC. The dateToTest is a date value I generate within a for loop.
I'm getting an invalid time value error where my date comparison is.
How do I handle this date comparison?
UPDATE:
Here's a screen shot of actual code where disabledDates["disableBefore"] is the value I'm getting from the API.
Related
I have a very simple SQL string that brings a Date field from sql:
SELECT dbo.table.effDate from table where.....
I need to convert that date to a date variable at Node so I can perform a calculation. This date is always the first of a month, so my results at SQL are
2023-01-01
2022-05-01
2022-08-01
etc.
So, when I try to convert the field to a node date type, in these different ways, I always get the previous date of the one at the field (for the example above)
2022-12-31
2022-04-30
2022-07-31
Im using:
let effDate = moment(response[i].effDate, 'YYYY-MM-DD').format('YYYY-MM-DD')
Then
let effDate = new Date(response[i].effDate)
even this is bringing me a previous date
let effDate = response[I].effDate.toString()
and this:
let effDate = new Date(response[I].effDate).toLocaleDateString('en-US')
I could fix this by adding one day to whatever SQL brings me back, but its not the point, I want to do it right.
I also tried using getTimezoneOffset
effDate = new Date(response[i].effdate.getTime() - response[i].effdate.getTimezoneOffset() * 60000)
But I always get the previous date.
What confuses me is that javascript UTC zones should have nothing to do when it comes to the value returned by SQL:
Again, I could just add a day but that wont be right, and I would like to know why this is happening (even using toString()).
Thanks.
Basically Date treats strings as being the UTC representation of that moment in time (because its the standard format to save a date in a database). Running the following line should give you a better understanding of this:
console.log(new Date('2023-01-01').toString())
I get:
Sat Dec 31 2022 16:00:00 GMT-0800 (Pacific Standard Time)
Either allow moment.js to interpret the string directly, or use the .utc() method.
// moment from Date object is still UTC, outputs local
console.log('A:', moment(new Date('2023-01-01')).format('YYYY-MM-DD'))
// moment parses string assumming local
console.log('B:', moment('2023-01-01').format('YYYY-MM-DD'))
// use moment.utc() method to keep output UTC
console.log('C:', moment(new Date('2023-01-01')).utc().format('YYYY-MM-DD'))
console.log('D:', moment.utc(new Date('2023-01-01')).format('YYYY-MM-DD'))
console.log('E:', moment.utc('2023-01-01').format('YYYY-MM-DD'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment.min.js"></script>
I have a date field coming from SQL as follows:
2022-06-30T00:00:00.000Z
Im trying to get the first 10 characters (date in format yyyy-mm-dd) from it, but I can't get it to work.
First, I tried a "left" function
textPaidThru= pt.slice(0,10)
And I got
Wed Jun 29
Then I tried moment
let textPaidThru = moment(paidThru).format('YYYY-MM-DD');
But Im getting this:
2022-06-29
No matter which method I try to use, I always get the provided date minus one day.
I encounter working with dates very hard in JS. Is there a way to get the date part only as provided by SQL? This is the value Im expecting:
2022-06-30
Thanks.
TL;DR; Timezones
Actual Answer
You could just use some vanilla javascript and parse it like this:
Note month is zero index in Date, so you will need to add 1 to each:
const dateToParse = "2022-06-30T00:00:00.000Z"
let parsedDate = new Date(dateToParse)
const formattedDate = `${parsedDate.getFullYear()}-${parsedDate.getMonth()+1}-${parsedDate.getDate()}`
console.log(formattedDate)
The reason you are getting 6-29 is most likely due to you not living in UTC+0. I get 6-29 as well, but that is because I live in UTC-7.
If you look in the code below I change the time to be UTC-7 (which should work for your timezone as well if what your profile says is correct UTC-3) and the console log for me displays 6-30 now.
const dateToParse = "2022-06-30T07:00:00.000Z"
let parsedDate = new Date(dateToParse)
const formattedDate = `${parsedDate.getFullYear()}-${parsedDate.getMonth()+1}-${parsedDate.getDate()}`
console.log(formattedDate)
If you know you'll always get the same format (well, you probably will), you can just use split, something like.
let dateTime = '2022-03-25T02:03:04.000Z';
let onlyDate = date.split('T')[0];
This will split the string at T and you basically only want the first part (array index 0) and that's it.
I have saved a datetime value created by Luxon into a postgres database column, of type TIMESTAMP(3). I want to then use that value, convert it into other time zones, etc. However, I can't seem to figure out how to "use" it.
I created the object using the following
const { DateTime } = require("luxon");
const myDate = DateTime.now().toUTC().toISO()
I then inserted it into a postgres database, into a column of type TIMESTAMP(3).
I extract it out of the database using a query. When I log it, it says its value is:
console.log(extracted_date); //=> "2021-12-27T09:57:16.184Z"
console.log(typeof extracted_date); //=> object
// The following return "unparsable" or undefined objects
DateTime.fromISO(extracted_date);
DateTime.fromObject(extracted_date);
I can find plenty of tutorials about how to insert dates into sql, but nothing on how to take that date object and actually do something with it. I want to, for instance, convert its time zone.
To use that date object you can initiate a new Date, like so:
console.log(extracted_date); //=> "2021-12-27T09:57:16.184Z"
const javascriptDate = new Date(extracted_date);
Than you can use it directly or with the luxon library.
console.log(javascriptDate.toGMTString()); // => "Mon, 27 Dec 2021 09:57:16 GMT"
console.log(javascriptDate.toISOString()); // => "2021-12-27T09:57:16.184Z"
console.log(javascriptDate.valueOf()); // => 1640599036184
This object core is actually, a value that represents milliseconds since 1 January 1970 UTC, and added to that are time and string parsing functions, generally speaking.
More Info
In some systems dates are store in the database as the value -
date.valueOf() - which make it clearer (for a developer) you have to manipulate it, and perhaps reduce problems of showing the wrong timestamp to users. In the other hand - you lose the readability. Another opion is using only UTC time in your system and convert the timestamp on client side or before presenting the data. The use of UTC will make sure all of your dates will have same language'.
If you want to read more about timestamp,
here are some references:
UTC vs ISO format for time
What is the "right" JSON date format?
I am getting 4 dates as inputs mentioned below from an external source.
Dates with time element:
"InitialDate": "2019-02-19T12:03:22.129Z",
"updateDate": "2019-02-28T05:26:57.115Z",
Dates without time element:
"startDate": "2019-02-18",
"endDate": "2020-02-16",
I am coverting InitialDate and updateDate and creating actualInitDatE out of them using a moment format as below, as they are getting time element also in it.
I don't want time element and i only want date elements of all the 4 dates.
const actualInitDatE = moment(InitialDate).format('MM-DD-YYYY') ||
moment(updateDate).format('MM-DD-YYYY');
Now, I am converting the startDate and endDate which are having only date element in it (and no time element) and finally creating actualStartDate and actualEndDateW variables,
const actualStartDateW = moment(startDate).format('MM-DD-YYYY');
const actualEndDateW = moment(endDate).format('MM-DD-YYYY');
Now I am comparing them with the below logic and is working fine in IST,
if (actualInitDatE >= actualStartDateW && actualInitDatE <= actualEndDateW) {
console.log('Compared and True');
}
My Doubt is will this work correctly in UTC and other time zones as well? I am doubtful because some of the dates have time elements and some of them have only the date elements.
I have gone through this and implemented the approach. Is this approach is correct or do we need to use any offset?
javascript Date timezone issue
Can someone help me in this regard and let me know if this code works across timeZones?
I believe the core issue here is that you must specify a timezone for startDate and endDate. If you don't, moment.js will assume local time, for example IST or let's say you were in the US, Pacific time. The problem with this approach is that the code will give inconsistent results (depending on the machine).
You can demonstrate this by running the snippet below in your browser (Chrome is best) and changing your machine timezone. You'll see that parsing the startDate (and endDate) would result in different times depending on your timezone.
So the combination of a timestamp and a timezone give us a clear, unambiguous point in time for the most robust code. If we don't set a timezone when parsing the start and end date, the code could give a different result depending on the machine it is running on.
The best approach is to specify what timezone the startDate and endDate are in, e.g. are they in IST, or in UTC?
This way you can be sure your dates will parse consistently.
I would also suggest creating a function, say, parseDate that accepts a datestring, a format, and a timezone. This is makes all assumptions clear to anyone who reads the code.
There is no issue with InitialDate or updateDate, since they are specified as UTC times (the Z timezone specifier), so they are both clear and unambiguous.
const dates = {
startDate: "2019-02-18",
endDate: "2020-02-16"
}
const startDateNoTimezoneSpecified = moment(dates.startDate);
console.log("StartDate (No Timezone Specified):", startDateNoTimezoneSpecified.toISOString());
function parseDate(dateString, format, timezone) {
return moment.tz(dateString, format, timezone)
}
// Parse start date, assuming it is in IST (I'm assuimg IST refers to India Standard Time , if it's Israel Standard Time replace with Asia/Jerusalem!
console.log("Parse date result (IST):", parseDate(dates.startDate, "YYYY-MM-DD","Asia/Kolkata").toISOString());
console.log("Parse date result (UTC):", parseDate(dates.startDate, "YYYY-MM-DD","UTC").toISOString());
// You can also use moment.utc instead of moment.tz(date, "UTC").. it's simpler!
const startDateUTC = moment.utc(dates.startDate);
console.log("StartDate (UTC (moment.utc)):", startDateUTC.toISOString());
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>
<script src="https://momentjs.com/downloads/moment-timezone-with-data-1970-2030.js"></script>
You seem to be over complicating things.
Your conversion of UTC timestamps to local dates is OK, but the format doesn't make sense. MM-DD-YYYY is pretty useless for anything, I'd suggest using ISO 8601 YYYY-MM-DD.
Date-only timestamps should be treated as local, so no conversion is necessary for the second two dates. Using ISO 8601 format, the strings can be compared directly:
let initialDate = '2019-02-19T12:03:22.129Z';
let updateDate = '2019-02-28T05:26:57.115Z';
// Get local date in required format
let actualInitDatE = moment(initialDate || updateDate).format('YYYY-MM-DD');
// Use these as they are
let startDate = '2019-02-18';
let endDate = '2020-02-16';
if (actualInitDatE >= startDate &&
actualInitDatE <= endDate) {
console.log('Compared and True');
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>
You can also keep the values as moment objects after setting them to the start of the day and use various moment methods for comparison, but I think the string version is pretty simple so why make it harder than it has to be?
Whether "this code works across timeZones" is unknown as you haven't explained what you are actually trying to achieve.
I'm trying to create a Date in NodeJS with zero time i.e. something like 2016-08-23T00:00:00.000Z. I tried the following code:
var dateOnly = new Date(2016, 7, 23, 0, 0, 0, 0);
console.log(dateOnly);
While I expected the output to be as mentioned above, I got this:
2016-08-22T18:30:00.000Z
How do I create a Date object like I wanted?
The key thing about JavaScript's Date type is that it gives you two different views of the same information: One in local time, and the other in UTC (loosely, GMT).
What's going on in your code is that new Date interprets its arguments as local time (in your timezone), but then the console displayed it in UTC (the Z suffix tells us that). Your timezone is apparently GMT+05:30, which is why the UTC version is five and a half hours earlier than the date/time you specified to new Date.
If you'd output that date as a string in your local timezone (e.g., from toString, or using getHours and such), you would have gotten all zeros for hours, minutes, seconds, and milliseconds. It's the same information (the date is the same point in time), just two different views of it.
So the key thing is to make sure you stick with just the one view of the date, both on input and output. So you can either:
Create it like you did and output it using the local timezone functions (toString, getHours, etc.), or
Created it via Date.UTC so it interprets your arguments in UTC, and then use UTC/GMT methods when displaying it such as toISOString, getUTCHours, etc.:
var dateOnlyInUTC = new Date(Date.UTC(2016, 7, 23));
console.log(dateOnlyInUTC.toISOString()); // "2016-08-23T00:00:00.000Z"
Side note: The hours, minutes, seconds, and milliseconds arguments of both new Date and Date.UTC default to 0, you don't need to specify them if you want zeroes there.
You could always just initialize the Date object with your desired date, then use the Date objects .setHours() method to set it to midnight.
See also:
What is the best way to initialize a JavaScript Date to midnight?