I'm having a javascript object as below.
var obj = { pageSize:"25",asOfDate:"Thu Sep 25 00:00:00 UTC+0530 2014"};
when i stringify it,
var d = JSON.stringify(obj);
its giving me result as
{"pageSize":"25","asOfDate":"2014-09-24T18:30:00Z"}
what could be the reason that its giving date 2014-09-24 than 2014-09-25 ?
EDIT:
My deployment server is located in US (Eastern Time UTC -5:00).when i check the site from my local machine in india its giving me date as 24 Sept 2014
UTC+0530 declares a UTC time offset. Seems that 5:30 is around the India or Sri Lanka area.
"2014-09-24T18:30:00Z" is the same as "Thu Sep 25 00:00:00 UTC+0530 2014" in two different formats. The Z in the first format is resolving to UTC (GMT) time, which in this case is -5:30. So 18:30 is 24:00 - 5:30.
So, if you are stringify-ing in a timezone that is negative offset (say in the United States UTC−08:00) then it could push the date back by one day when parsing.
I think this is what you are seeing.
Related SO Question: JSON Stringify changes time of date because of UTC
Try this
var obj = { pageSize:"25",asOfDate:"Thu Sep 25 00:00:00 UTC+0530 2014"};
obj.asOfDate = reverseUTC(obj.asOfDate);
var d = JSON.stringify(obj);
function reverseUTC(updatedDate) {
if ($.isEmptyObject(updatedDate)) {
var offset = updatedDate.getTimezoneOffset();
var currentDateTime = new Date();
updatedDate.setHours((currentDateTime.getHours() * 60 + currentDateTime.getMinutes() - offset) / 60);
updatedDate.setMinutes((currentDateTime.getHours() * 60 + currentDateTime.getMinutes() - offset) % 60);
return updatedDate;
}
}
There is no standard format for passing dates in JSON, so JSON.stringify is just calling the default date.prototype.toString() method and that is taking the timezone into account.
You need to ensure that the date is converted into a string to your particular requirements and only convert to JSON format.
Related
In angular I have to save data to database in this time format 20160422060933.0Z ?
Someone told me that this is Microsoft time format. I don't know how to convert date to this format, anyone encountered this before?
2016 is a year, 04 is a month, and 22 is a date but i don't know what 060933.0Z is. We use Dreamfactory API and SQL Server
Later edit: based on another answer, actually this seems to be a standard format colloquially called a "LDAP date". See Converting a ldap date for some details on the format (and how to parse it in Java). It can for sure be easily parsed with any typical JS date library or even without any library.
Let's break it down into pieces.
2016 = full year
04 = month, padded to 2 digits
22 = day of month, likely also padded to 2 digits
06 = hour of day, padded to 2 digits, likely on a 24h scale
09 = minute of the hour, padded to 2 digits
33 = second of the minute, likely padded to 2 digits
. = literal
0 = probably "second fraction"
Z = offset from UTC. Z meaning UTC.
Parsing it
You have several options to parse it:
If you assume you're going to always get an UTC datetime from the backend, you can naively parse it in JavaScript just by extracting the relevant substrings.
const input = '20160422060933.0Z';
new Date(Date.UTC(
input.substr(0, 4), // year
input.substr(4, 2) - 1, // month is 0-indexed
input.substr(6, 2), // day
input.substr(8, 2), // hour
input.substr(10, 2), // minute
input.substr(12, 2), // second
("0." + input.split(/[.Z]/gi)[1]) * 1000 // ms
));
// Fri Apr 22 2016 09:09:33 GMT+0300 (Eastern European Summer Time)
You can be a little creative and actually manipulate the string into an ISO format. Then you can just use the native Date.parse function, which supports parsing ISO strings (other formats are browser-dependent). The advantage is that it'll support dates that are not UTC as well.
new Date(Date.parse(
input.substr(0, 4) + "-" + // year, followed by minus
input.substr(4, 2) + "-" + // month, followed by minus
input.substr(6, 2) + "T" + // day, followed by minus
input.substr(8, 2) + ":" + // hour, followed by color
input.substr(10, 2) + ":" + // minute, followed by color
input.substr(12, 2) + // second
input.substr(14) // the rest of the string, which would include the fraction and offset.
))
// Fri Apr 22 2016 09:09:33 GMT+0300 (Eastern European Summer Time)
Use a library like luxon, momentjs, etc. This you might already have a JS library in your project. You'd need to build a date format pattern to parse this format into a native Date object or some other library-specific object. For example, with momentjs you'd do:
moment("20160422060933.0Z", "YYYYMMDDHHmmss.SZ")
// Fri Apr 22 2016 09:09:33 GMT+0300 (Eastern European Summer Time)
Formatting into it
This side of the operation is even simpler.
Without any date library, you just need to get rid of the "-", ":" and "T" separators from the ISO format. So you can just do the following:
new Date().toISOString().replace(/[:T-]/g, "")
// '20230209175305.421Z'
If you want to use a date library, then you just do the reverse, format operation using the same pattern as for parsing. Eg. in momentjs:
moment(new Date()).utc().format("YYYYMMDDHHmmss.S[Z]")
// "20230209175222.5Z"
(note that I needed to place the "Z" in brackets due to https://github.com/moment/moment-timezone/issues/213).
Just a side note to the other answer here:
You can use ldap2date npm package for parsing, should be not that "heavy" as moment.
Code:
import ldap2date from "ldap2date";
// or import { parse, toGeneralizedTime } from "ldap2date";
const dateString = "20160422060933.0Z";
const date = ldap2date.parse(dateString);
console.log(date.toUTCString());
// Fri, 22 Apr 2016 06:09:33 GMT
const str = ldap2date.toGeneralizedTime(date);
console.log(str);
// 20160422060933Z (note: no period.)
console.log(str.replace("Z", ".0Z"));
// 20160422060933.0Z
function getLdapString(date) {
return ldap2date.toGeneralizedTime(date);
}
const d = new Date();
console.log(getLdapString(d), d.toISOString());
// 20230209181603.965Z 2023-02-09T18:16:03.965Z
And some monkey-patching to match "format":
function getLdapString(date) {
return date.getMilliseconds() !== 0
? ldap2date.toGeneralizedTime(date)
: ldap2date.toGeneralizedTime(date).replace("Z", ".0Z");
}
const d = new Date();
d.setMilliseconds(15);
const d1 = new Date();
d1.setMilliseconds(0);
console.log("Date with milliseconds: ", d.toUTCString(), getLdapString(d));
console.log("Date without milliseconds: ", d1.toUTCString(), getLdapString(d1));
// Date with milliseconds: Thu, 09 Feb 2023 18:22:27 GMT 20230209182227.15Z
// Date without milliseconds: Thu, 09 Feb 2023 18:22:27 GMT 20230209182227.0Z
Or to ignore milliseconds part completelly
function getLdapString(date) {
const copy = new Date(date);
copy.setMilliseconds(0);
return ldap2date.toGeneralizedTime(copy).replace("Z", ".0Z");
}
console.log("Date with milliseconds: ", d.toUTCString(), getLdapString(d));
console.log("Date without milliseconds: ", d1.toUTCString(), getLdapString(d1));
// Date with milliseconds: Thu, 09 Feb 2023 18:29:50 GMT 20230209182950.0Z
// Date without milliseconds: Thu, 09 Feb 2023 18:29:50 GMT 20230209182950.0Z
I'm assign a new date object to my object attribute like that :
giftObject.purshasedDate = new Date()
which give a date format :
Date Thu Feb 20 2020 13:36:37 GMT+0100 (heure normale d’Europe
centrale)
I want to increase this date by one year, I tried :
new Date().setFullYear(giftObject.purshasedDate.getFullYear() + 1) but it give a number serial like this : 1613824899244
I do not understand what that number serial mean! it's a date or should a try some thing else ?
By default all dates object are timestamps.
JavaScript Date objects represent a single moment in time in a
platform-independent format. Date objects contain a Number that
represents milliseconds since 1 January 1970 UTC.
Source : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date
I think the default new Date() object can display itself to string by in fact it's also a timestamp.
If you want to display a date as string, you have to use the toLocaleString() method on Date.
I tried by updating the original date and it return the string of the date, don't know why but it's work by updating the original date.
Example :
let giftObject = {};
giftObject.purshasedDate = new Date();
giftObject.purshasedDate.setFullYear(giftObject.purshasedDate.getFullYear() + 1);
console.log(giftObject.purshasedDate)
Result : "20/02/2021 à 13:55:49" for my French browser
const oldDate = new Date("Date Thu Feb 20 2020 13:36:37 GMT+0100")
const newDate = oldDate.setFullYear(oldDate.getFullYear() + 1)
const dateWithPlusOneYear = new Date(newDate)
console.log(new Date(dateWithPlusOneYear))
//Sat Feb 20 2021 13:36:37 GMT+0100 (Central European Standard Time)
Please use this one:
purshasedDate = new Date();
purshasedDate = new Date(purshasedDate.setFullYear(purshasedDate.getFullYear() + 1));
A response I'm getting from the server is a 'local' timestamp.
Which would mean my local time expressed as UTC milliseconds, but without the UTC offset.
For example: 1537747200000 is Mon Sep 24 2018 00:00:00 UTC
Mon Sep 24 2018 03:00:00 EEST (my local time), but in my context, this date is actually Mon Sep 24 2018 00:00:00 EEST, so the utc value with my timezone.
I would now like to display this using moment and moment-timezone if needed.
So what I would like to know is how to create a new moment object that takes in "LOCAL milliseconds"? so I'd pass 1537747200000 and my local time zone if needed, and I could display it as Mon Sep 24 2018 00:00:00 EEST
I found that using moment timezone + utcOffset does the trick, but I don't really know if this is a good approach. utc offset docs says this:
Setting the UTC offset by supplying minutes. Note that once you set an offset, it's fixed and won't change on its own (i.e there are no DST rules). If you want an actual time zone -- time in a particular location, like America/Los_Angeles, consider moment-timezone.
Another approach would be to format the moment to ISOString moment(1537747200000).toISOString() and then parse the resulting string, without the timezone information (the 'z'). When parsing a string, you can parse it in another timezone. moment.tz(moment(1537747200000).toISOString().slice(0, -1), tz). But this requires that I parse->format->parse the value, so it's a lot of extra operations.
const [one, two, thr] = ["exp","tr","appr"];
const display = (toAdd, id) => document.getElementById(id).innerHTML += `<br/> ${toAdd}`;
const formatString = "MMM D, YYYY HH:mm z";
const tz = moment.tz.guess();
const millis_24_sep_00_00_utc = moment.utc("24-09-2018", "DD-MM-YYYY", true).valueOf(); //1537747200000
const isoString = moment(millis_24_sep_00_00_utc).toISOString();
//exp
display(tz, one);
display(millis_24_sep_00_00_utc, one);
const ex = moment.tz(millis_24_sep_00_00_utc, tz).utc().format("MMM D, YYYY HH:mm")
display(`${ex} ${moment().tz(tz).zoneAbbr()} <- local tz`, one);
//tr
[
moment(millis_24_sep_00_00_utc).tz(tz),
moment.utc(new Date(millis_24_sep_00_00_utc)).tz(tz),
moment.tz(millis_24_sep_00_00_utc, tz).utc(),
moment.tz(isoString, tz),
]
.forEach(mom => display(mom.format(formatString), two));
//some approaches
[
//setting utcOffset to 0
moment.tz(millis_24_sep_00_00_utc, tz).utcOffset(0),
//iso string to transform millis -> string -> parse the string in another tz
moment.tz(isoString.slice(0, -1), tz),
]
.forEach(mom => display(mom.format(formatString), thr));
<!DOCTYPE html>
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.19.1/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.21/moment-timezone-with-data.js"></script>
<title>Test</title>
</head>
<body>
<div id="exp">EXPECTED</div>
<hr/>
<div id="tr">TRIES</div>
<hr/>
<div id="appr">APPROACHES</div>
</body>
</html>
It's unusual to provide a millisecond time value that has been offset. But if your time values are offset by +3 hours then you can subtract 3 hours worth of milliseconds (1.08e7) and use it as a UTC time value.
E.g. A time value of 1537747200000 typically represents 2018-09-24T00:00:00.000Z. If that time value actually represents 2018-09-24T00:00:00.000+0300, then the equivalent UTC time value is:
1537747200000 - 1.08e7 = 1537736400000;
Working example:
var d = new Date(1537747200000 - 1.08e7);
console.log(`Zulu: ${d.toISOString()}\nLocal: ${d.toString()}`);
I'm calculating the dates for my application like date,week,month.
First I am defining day,week,month,custom like:
this.reportTypes = [{TypeId: 1, Type: 'Day'}, {TypeId: 6, Type: 'Week'}, {TypeId: 30, Type: 'Month'}, {
TypeId: 10,
Type: 'Custom'
}]
Next I'm defining dates like:
var currdate = new Date();
if(reportType==1){
// this.reportDataFromDate=currdate;
// this.reportDataToDate=currdate;
//This is for setting the current date
this.reportDataFromDate= currdate;
this.reportDataToDate= currdate;
}
else if(reportType==30){
var First = new Date(currdate.getFullYear(),currdate.getMonth(),1);
this.reportDataFromDate=First;
this.reportDataToDate=currdate;
}
else if(reportType!=10){
var last = new Date(currdate.getTime() - (reportType * 24 * 60 * 60 * 1000));
this.reportDataFromDate=last;
this.reportDataToDate=currdate;
}
}
The problem is after selecting reportType == 30 then it has to get the first day of the month.
It is showing the date as 1-Dec-2017 but it is getting the data of till 30th November 2017?
This is screenshot of the SQL server. I'm sending the date as 1st Dec 2017 but it is getting 30-11-2017.
When the Date() constructor is invoked with integers, the result is a date object with that date assumed your systems (read browser/os) timezone.
Example:
let d = new Date(2017);
// returns Thu Jan 01 1970 01:00:02 GMT+0100 (W. Europe Standard Time)
// and with d.toUTCString(): Fri, 30 Dec 2016 23:00:00 GMT
Which may end up in an entire different year when sending to the server
Using the string constructor and specifying timezone will help you overcome this.
Example:
let d = new Date('2017z');
// returns Sun Jan 01 2017 01:00:00 GMT+0100 (W. Europe Standard Time)
// and with d.toUTCString(): Sun, 01 Jan 2017 00:00:00 GMT
The latter which is what you should pass to a server, and normally do calculations on.
However, note that calculations with dates are a complicated matter best left to a library like moment.js. To get a feel of what you are dealing with have a look at this great talk from the WebRebel conference.
So to actually give an answer to your title, try this example which creates the date in a simple string using UTC:
let d = new Date(currdate.getUTCFullYear() + ' ' +(currdate.getUTCMonth() + 1) + ' 1z');
d.getUTCDay(); // returns the day as an integer where Monday is 0.
Note that we add 1 month due to getUTCMonth() returns January as 0.
Why the difference?
The new Date(x,y,z) constructor treats the parameters as local date values.
See MDB Web Docs - Date
Note: Where Date is called as a constructor with more than one argument, the specifed arguments represent local time. If UTC is desired, use new Date(Date.UTC(...)) with the same arguments.
But, under the hood the date is stored as UTC (milliseconds since 1 Jan 1970).
const date = new Date(2017, 11, 29);
console.log('valueOf()', date.valueOf()) // 1514458800000
and the UTC date is different to your local date (see trailing 'Z' indicates UTC)
const date = new Date(2017, 11, 29);
console.log('date', date) // "2017-12-28T11:00:00.000Z" (trailing 'Z' means UTC)
// The difference in minutes between browser local and UTC
console.log('getTimezoneOffset()', date.getTimezoneOffset() )
and when you send it to the server, JSON sends it as UTC
const date = new Date(2017, 11, 29);
console.log('JSON', date.toJSON())
// JSON will yield string version of UTC === 2017-12-28T11:00:00.000Z
How to fix it
Well, you might decide that you actually want the date/time in local, and conclude it's not broken.
But if you want to send UTC to the server, wrap the parameters in Date.UTC()
const date = new Date(Date.UTC( 2017, 11, 29 ))
console.log('date.toJSON()', date.toJSON() ) // 2017-12-29T00:00:00.000Z
What about month parameter === 11?
From the MDB page referenced above,
Note: The argument month is 0-based. This means that January = 0 and December = 11.
If you are using .Net Web API as backend, you can config the timezone in Web API WebApiconfig.cs like below. It will serialize the time in UTC.
public static void Register(HttpConfiguration config)
{
config.Formatters.JsonFormatter.SerializerSettings.DateTimeZoneHandling = Newtonsoft.Json.DateTimeZoneHandling.Utc;
}
Or use
config.Formatters.JsonFormatter.SerializerSettings.DateTimeZoneHandling = Newtonsoft.Json.DateTimeZoneHandling.RoundtripKind; //Time zone information should be preserved when converting.
Let's say I have two different types of date strings - a mysql date stamp, and a mysql date+time stamp.
"2015-12-25"
"2015-12-25 00:00:00"
When I parse these in JavaScript, I get:
new Date("2015-12-25");
Thu Dec 24 2015 19:00:00 GMT-0500 (Eastern Standard Time)
new Date("2015-12-25 00:00:00");
Fri Dec 25 2015 00:00:00 GMT-0500 (Eastern Standard Time)
Or, in UTC:
new Date("2015-12-25").toUTCString();
"Fri, 25 Dec 2015 00:00:00 GMT"
new Date("2015-12-25 00:00:00").toUTCString();
"Fri, 25 Dec 2015 05:00:00 GMT"
Adding the time on the end somehow makes the date parse as being my-time-zone hours ahead. What I want is some kind of function to make these both parse as the same thing - GMT or no, I can adjust, as long as the outcome is known to be one or the other, no matter the date string passed in.
I got halfway through implementing a solution involving regexes and detecting date format before I figured that there is probably a better way to go about this.
I've found some solutions involving Date.prototype.getTimezoneOffset(), but for both of these dates that returns the same thing, since they are parsed as being in the same timezone.
Any ideas?
ECMAScript ed 5.1 (aka ES5) required that ISO 8601 date strings be parsed as UTC, however ISO required them to be parsed as local. Now the current ECMAScript standard (version 6) is consistent with ISO and requires ISO compliant strings with no timezone to be parsed as local.
<update> ECMAScript 2016 (ed 7) changed again so that YYYY-MM-DD format date strings are parsed as UTC, so no longer consistent with ISO 8601.</update>.
So whether you get one behaviour or the other depends on the browser (and if you try it with IE 8 you'll get NaN). Prior to ES5, parsing of all strings was implementation dependent.
"2015-12-25" is a valid ISO 8601 string with no timezone, so should be treated as UTC under ES5 rules and local by ed 6 rules.
"2015-12-25 00:00:00" is not a valid ISO string (missing the "T" between the date and time) so browsers can parse it however they like (parsing of non–ISO strings is implementation dependent in all versions of ECMAScript).
The bottom line is do not use the Date constructor to parse strings (or Date.parse). Parse them yourself.
To parse ISO-like strings, use something like the following. It treats strings with not offset as UTC (per ES5), however perhaps that should now be changed to be local:
/**
* Parse an ISO string with or without an offset
* e.g. '2014-04-02T20:00:00-0600'
* '2014-04-02T20:00:00Z'
* '2014-02'
*
* Allows decimal seconds if supplied
* e.g. '2014-04-02T20:00:00.123-0600'
*
* If no offset is supplied (or it's Z), treat as UTC (per ECMA-262)
*
* If date only, e.g. '2014-04-02' or '2014-02', treat as UTC date (per ECMA-262)
* All parts after year are optional
* Don't allow two digit years to be converted to 20th century years
* #param {string} s - ISO 860 date string
*/
function parseISOString(s) {
var invalidDate = new Date(NaN);
var t = s.split(/\D+/g);
var hasOffset = /[-+]\d{4}$/.test(s);
// Whether decimal seconds are present changes the offset field and ms value
var hasDecimalSeconds = /[T ]\d{2}:\d{2}:\d{2}\.\d+/i.test(s);
var offset = hasDecimalSeconds? t[7] : t[6];
var offSign;
var yr = +t[0],
mo = t[1]? --t[1] : 0,
da = +t[2] || 1,
hr = +t[3] || 0,
min = +t[4] || 0,
sec = +t[5] || 0,
ms = hasDecimalSeconds? +t[6] : 0,
offSign = hasOffset? /-\d{4}$/.test(s)? 1 : -1 : 0,
offHr = hasOffset? offset/100 | 0 : 0,
offMin = hasOffset? offset%100 : 0;
// Ensure time values are in range, otherwise invalid date.
// Values can't be -ve as splitting on non-digit character
if (hr > 24 || min > 59 || sec > 59 || ms > 1000 || offHr > 24 || offMin > 59){
return invalidDate;
}
// Create a date object from date parts, check for validity
// Avoid two digit years being converted to 20th century
var d = new Date();
d.setUTCFullYear(yr, mo, da);
// Check that date values are valid
if (d.getUTCFullYear() != yr || d.getUTCDate() != da) {
return invalidDate;
}
// If there's an offset, apply it to minutes to get a UTC time value
min = hasOffset? +min + offSign * (offHr * 60 + offMin) : min;
// Set UTC time values of d
d.setUTCHours(hr, min, sec, ms);
return d;
}
It can be reduced to less than half that, but it's written to be easy to read and maintain.