Related
I'm taking my first crack at Ajax with jQuery. I'm getting my data onto my page, but I'm having some trouble with the JSON data that is returned for Date data types. Basically, I'm getting a string back that looks like this:
/Date(1224043200000)/
From someone totally new to JSON - How do I format this to a short date format? Should this be handled somewhere in the jQuery code? I've tried the jQuery.UI.datepicker plugin using $.datepicker.formatDate() without any success.
FYI: Here's the solution I came up with using a combination of the answers here:
function getMismatch(id) {
$.getJSON("Main.aspx?Callback=GetMismatch",
{ MismatchId: id },
function (result) {
$("#AuthMerchId").text(result.AuthorizationMerchantId);
$("#SttlMerchId").text(result.SettlementMerchantId);
$("#CreateDate").text(formatJSONDate(Date(result.AppendDts)));
$("#ExpireDate").text(formatJSONDate(Date(result.ExpiresDts)));
$("#LastUpdate").text(formatJSONDate(Date(result.LastUpdateDts)));
$("#LastUpdatedBy").text(result.LastUpdateNt);
$("#ProcessIn").text(result.ProcessIn);
}
);
return false;
}
function formatJSONDate(jsonDate) {
var newDate = dateFormat(jsonDate, "mm/dd/yyyy");
return newDate;
}
This solution got my object from the callback method and displayed the dates on the page properly using the date format library.
eval() is not necessary. This will work fine:
var date = new Date(parseInt(jsonDate.substr(6)));
The substr() function takes out the /Date( part, and the parseInt() function gets the integer and ignores the )/ at the end. The resulting number is passed into the Date constructor.
I have intentionally left out the radix (the 2nd argument to parseInt); see my comment below.
Also, I completely agree with Rory's comment: ISO-8601 dates are preferred over this old format - so this format generally shouldn't be used for new development.
For ISO-8601 formatted JSON dates, just pass the string into the Date constructor:
var date = new Date(jsonDate); //no ugly parsing needed; full timezone support
You can use this to get a date from JSON:
var date = eval(jsonDate.replace(/\/Date\((\d+)\)\//gi, "new Date($1)"));
And then you can use a JavaScript Date Format script (1.2 KB when minified and gzipped) to display it as you want.
For those using Newtonsoft Json.NET, read up on how to do it via Native JSON in IE8, Firefox 3.5 plus Json.NET.
Also the documentation on changing the format of dates written by Json.NET is useful:
Serializing Dates with Json.NET
For those that are too lazy, here are the quick steps. As JSON has a loose DateTime implementation, you need to use the IsoDateTimeConverter(). Note that since Json.NET 4.5 the default date format is ISO so the code below isn't needed.
string jsonText = JsonConvert.SerializeObject(p, new IsoDateTimeConverter());
The JSON will come through as
"fieldName": "2009-04-12T20:44:55"
Finally, some JavaScript to convert the ISO date to a JavaScript date:
function isoDateReviver(value) {
if (typeof value === 'string') {
var a = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)(?:([\+-])(\d{2})\:(\d{2}))?Z?$/.exec(value);
if (a) {
var utcMilliseconds = Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4], +a[5], +a[6]);
return new Date(utcMilliseconds);
}
}
return value;
}
I used it like this
$("<span />").text(isoDateReviver(item.fieldName).toLocaleString()).appendTo("#" + divName);
The original example:
/Date(1224043200000)/
does not reflect the formatting used by WCF when sending dates via WCF REST using the built-in JSON serialization. (at least on .NET 3.5, SP1)
I found the answer here helpful, but a slight edit to the regex is required, as it appears that the timezone GMT offset is being appended onto the number returned (since 1970) in WCF JSON.
In a WCF service I have:
[OperationContract]
[WebInvoke(
RequestFormat = WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json,
BodyStyle = WebMessageBodyStyle.WrappedRequest
)]
ApptVisitLinkInfo GetCurrentLinkInfo( int appointmentsId );
ApptVisitLinkInfo is defined simply:
public class ApptVisitLinkInfo {
string Field1 { get; set; }
DateTime Field2 { get; set; }
...
}
When "Field2" is returned as Json from the service the value is:
/Date(1224043200000-0600)/
Notice the timezone offset included as part of the value.
The modified regex:
/\/Date\((.*?)\)\//gi
It's slightly more eager and grabs everything between the parens, not just the first number. The resulting time sinze 1970, plus timezone offset can all be fed into the eval to get a date object.
The resulting line of JavaScript for the replace is:
replace(/\/Date\((.*?)\)\//gi, "new Date($1)");
Don't repeat yourself - automate date conversion using $.parseJSON()
Answers to your post provide manual date conversion to JavaScript dates. I've extended jQuery's $.parseJSON() just a little bit, so it's able to automatically parse dates when you instruct it to. It processes ASP.NET formatted dates (/Date(12348721342)/) as well as ISO formatted dates (2010-01-01T12.34.56.789Z) that are supported by native JSON functions in browsers (and libraries like json2.js).
Anyway. If you don't want to repeat your date conversion code over and over again I suggest you read this blog post and get the code that will make your life a little easier.
Click here to check the Demo
JavaScript/jQuery
var = MyDate_String_Value = "/Date(1224043200000)/"
var value = new Date
(
parseInt(MyDate_String_Value.replace(/(^.*\()|([+-].*$)/g, ''))
);
var dat = value.getMonth() +
1 +
"/" +
value.getDate() +
"/" +
value.getFullYear();
Result - "10/15/2008"
If you say in JavaScript,
var thedate = new Date(1224043200000);
alert(thedate);
you will see that it's the correct date, and you can use that anywhere in JavaScript code with any framework.
Updated
We have an internal UI library that has to cope with both Microsoft's ASP.NET built-in JSON format, like /Date(msecs)/, asked about here originally, and most JSON's date format including JSON.NET's, like 2014-06-22T00:00:00.0. In addition we need to cope with oldIE's inability to cope with anything but 3 decimal places.
We first detect what kind of date we're consuming, parse it into a normal JavaScript Date object, then format that out.
1) Detect Microsoft Date format
// Handling of Microsoft AJAX Dates, formatted like '/Date(01238329348239)/'
function looksLikeMSDate(s) {
return /^\/Date\(/.test(s);
}
2) Detect ISO date format
var isoDateRegex = /^(\d\d\d\d)-(\d\d)-(\d\d)T(\d\d):(\d\d):(\d\d)(\.\d\d?\d?)?([\+-]\d\d:\d\d|Z)?$/;
function looksLikeIsoDate(s) {
return isoDateRegex.test(s);
}
3) Parse MS date format:
function parseMSDate(s) {
// Jump forward past the /Date(, parseInt handles the rest
return new Date(parseInt(s.substr(6)));
}
4) Parse ISO date format.
We do at least have a way to be sure that we're dealing with standard ISO dates or ISO dates modified to always have three millisecond places (see above), so the code is different depending on the environment.
4a) Parse standard ISO Date format, cope with oldIE's issues:
function parseIsoDate(s) {
var m = isoDateRegex.exec(s);
// Is this UTC, offset, or undefined? Treat undefined as UTC.
if (m.length == 7 || // Just the y-m-dTh:m:s, no ms, no tz offset - assume UTC
(m.length > 7 && (
!m[7] || // Array came back length 9 with undefined for 7 and 8
m[7].charAt(0) != '.' || // ms portion, no tz offset, or no ms portion, Z
!m[8] || // ms portion, no tz offset
m[8] == 'Z'))) { // ms portion and Z
// JavaScript's weirdo date handling expects just the months to be 0-based, as in 0-11, not 1-12 - the rest are as you expect in dates.
var d = new Date(Date.UTC(m[1], m[2]-1, m[3], m[4], m[5], m[6]));
} else {
// local
var d = new Date(m[1], m[2]-1, m[3], m[4], m[5], m[6]);
}
return d;
}
4b) Parse ISO format with a fixed three millisecond decimal places - much easier:
function parseIsoDate(s) {
return new Date(s);
}
5) Format it:
function hasTime(d) {
return !!(d.getUTCHours() || d.getUTCMinutes() || d.getUTCSeconds());
}
function zeroFill(n) {
if ((n + '').length == 1)
return '0' + n;
return n;
}
function formatDate(d) {
if (hasTime(d)) {
var s = (d.getMonth() + 1) + '/' + d.getDate() + '/' + d.getFullYear();
s += ' ' + d.getHours() + ':' + zeroFill(d.getMinutes()) + ':' + zeroFill(d.getSeconds());
} else {
var s = (d.getMonth() + 1) + '/' + d.getDate() + '/' + d.getFullYear();
}
return s;
}
6) Tie it all together:
function parseDate(s) {
var d;
if (looksLikeMSDate(s))
d = parseMSDate(s);
else if (looksLikeIsoDate(s))
d = parseIsoDate(s);
else
return null;
return formatDate(d);
}
The below old answer is useful for tying this date formatting into jQuery's own JSON parsing so you get Date objects instead of strings, or if you're still stuck in jQuery <1.5 somehow.
Old Answer
If you're using jQuery 1.4's Ajax function with ASP.NET MVC, you can turn all DateTime properties into Date objects with:
// Once
jQuery.parseJSON = function(d) {return eval('(' + d + ')');};
$.ajax({
...
dataFilter: function(d) {
return d.replace(/"\\\/(Date\(-?\d+\))\\\/"/g, 'new $1');
},
...
});
In jQuery 1.5 you can avoid overriding the parseJSON method globally by using the converters option in the Ajax call.
http://api.jquery.com/jQuery.ajax/
Unfortunately you have to switch to the older eval route in order to get Dates to parse globally in-place - otherwise you need to convert them on a more case-by-case basis post-parse.
There is no built in date type in JSON. This looks like the number of seconds / milliseconds from some epoch. If you know the epoch you can create the date by adding on the right amount of time.
I also had to search for a solution to this problem and eventually I came across moment.js which is a nice library that can parse this date format and many more.
var d = moment(yourdatestring)
It saved some headache for me so I thought I'd share it with you. :)
You can find some more info about it here: http://momentjs.com/
I ended up adding the "characters into Panos's regular expression to get rid of the ones generated by the Microsoft serializer for when writing objects into an inline script:
So if you have a property in your C# code-behind that's something like
protected string JsonObject { get { return jsSerialiser.Serialize(_myObject); }}
And in your aspx you have
<script type="text/javascript">
var myObject = '<%= JsonObject %>';
</script>
You'd get something like
var myObject = '{"StartDate":"\/Date(1255131630400)\/"}';
Notice the double quotes.
To get this into a form that eval will correctly deserialize, I used:
myObject = myObject.replace(/"\/Date\((\d+)\)\/"/g, 'new Date($1)');
I use Prototype and to use it I added
String.prototype.evalJSONWithDates = function() {
var jsonWithDates = this.replace(/"\/Date\((\d+)\)\/"/g, 'new Date($1)');
return jsonWithDates.evalJSON(true);
}
In jQuery 1.5, as long as you have json2.js to cover for older browsers, you can deserialize all dates coming from Ajax as follows:
(function () {
var DATE_START = "/Date(";
var DATE_START_LENGTH = DATE_START.length;
function isDateString(x) {
return typeof x === "string" && x.startsWith(DATE_START);
}
function deserializeDateString(dateString) {
var dateOffsetByLocalTime = new Date(parseInt(dateString.substr(DATE_START_LENGTH)));
var utcDate = new Date(dateOffsetByLocalTime.getTime() - dateOffsetByLocalTime.getTimezoneOffset() * 60 * 1000);
return utcDate;
}
function convertJSONDates(key, value) {
if (isDateString(value)) {
return deserializeDateString(value);
}
return value;
}
window.jQuery.ajaxSetup({
converters: {
"text json": function(data) {
return window.JSON.parse(data, convertJSONDates);
}
}
});
}());
I included logic that assumes you send all dates from the server as UTC (which you should); the consumer then gets a JavaScript Date object that has the proper ticks value to reflect this. That is, calling getUTCHours(), etc. on the date will return the same value as it did on the server, and calling getHours() will return the value in the user's local timezone as determined by their browser.
This does not take into account WCF format with timezone offsets, though that would be relatively easy to add.
Using the jQuery UI datepicker - really only makes sense if you're already including jQuery UI:
$.datepicker.formatDate('MM d, yy', new Date(parseInt('/Date(1224043200000)/'.substr(6))));
output:
October 15, 2008
Don't over-think this. Like we've done for decades, pass a numeric offset from the de-facto standard epoch of 1 Jan 1970 midnight GMT/UTC/&c in number of seconds (or milliseconds) since this epoch. JavaScript likes it, Java likes it, C likes it, and the Internet likes it.
Everyone of these answers has one thing in common: they all store dates as a single value (usually a string).
Another option is to take advantage of the inherent structure of JSON, and represent a date as list of numbers:
{ "name":"Nick",
"birthdate":[1968,6,9] }
Of course, you would have to make sure both ends of the conversation agree on the format (year, month, day), and which fields are meant to be dates,... but it has the advantage of completely avoiding the issue of date-to-string conversion. It's all numbers -- no strings at all. Also, using the order: year, month, day also allows proper sorting by date.
Just thinking outside the box here -- a JSON date doesn't have to be stored as a string.
Another bonus to doing it this way is that you can easily (and efficiently) select all records for a given year or month by leveraging the way CouchDB handles queries on array values.
Posting in awesome thread:
var d = new Date(parseInt('/Date(1224043200000)/'.slice(6, -2)));
alert('' + (1 + d.getMonth()) + '/' + d.getDate() + '/' + d.getFullYear().toString().slice(-2));
Just to add another approach here, the "ticks approach" that WCF takes is prone to problems with timezones if you're not extremely careful such as described here and in other places. So I'm now using the ISO 8601 format that both .NET & JavaScript duly support that includes timezone offsets. Below are the details:
In WCF/.NET:
Where CreationDate is a System.DateTime; ToString("o") is using .NET's Round-trip format specifier that generates an ISO 8601-compliant date string
new MyInfo {
CreationDate = r.CreationDate.ToString("o"),
};
In JavaScript
Just after retrieving the JSON I go fixup the dates to be JavaSript Date objects using the Date constructor which accepts an ISO 8601 date string...
$.getJSON(
"MyRestService.svc/myinfo",
function (data) {
$.each(data.myinfos, function (r) {
this.CreatedOn = new Date(this.CreationDate);
});
// Now each myinfo object in the myinfos collection has a CreatedOn field that is a real JavaScript date (with timezone intact).
alert(data.myinfos[0].CreationDate.toLocaleString());
}
)
Once you have a JavaScript date you can use all the convenient and reliable Date methods like toDateString, toLocaleString, etc.
var newDate = dateFormat(jsonDate, "mm/dd/yyyy");
Is there another option without using the jQuery library?
This may can also help you.
function ToJavaScriptDate(value) { //To Parse Date from the Returned Parsed Date
var pattern = /Date\(([^)]+)\)/;
var results = pattern.exec(value);
var dt = new Date(parseFloat(results[1]));
return (dt.getMonth() + 1) + "/" + dt.getDate() + "/" + dt.getFullYear();
}
I get the date like this:
"/Date(1276290000000+0300)/"
In some examples the date is in slightly different formats:
"/Date(12762900000000300)/"
"Date(1276290000000-0300)"
etc.
So I came up with the following RegExp:
/\/+Date\(([\d+]+)\)\/+/
and the final code is:
var myDate = new Date(parseInt(jsonWcfDate.replace(/\/+Date\(([\d+-]+)\)\/+/, '$1')));
Hope it helps.
Update:
I found this link from Microsoft:
How do I Serialize Dates with JSON?
This seems like the one we are all looking for.
Below is a pretty simple solution for parsing JSON dates. Use the below functions as per your requirement. You just need to pass the JSON format Date fetched as a parameter to the functions below:
function JSONDate(dateStr) {
var m, day;
jsonDate = dateStr;
var d = new Date(parseInt(jsonDate.substr(6)));
m = d.getMonth() + 1;
if (m < 10)
m = '0' + m
if (d.getDate() < 10)
day = '0' + d.getDate()
else
day = d.getDate();
return (m + '/' + day + '/' + d.getFullYear())
}
function JSONDateWithTime(dateStr) {
jsonDate = dateStr;
var d = new Date(parseInt(jsonDate.substr(6)));
var m, day;
m = d.getMonth() + 1;
if (m < 10)
m = '0' + m
if (d.getDate() < 10)
day = '0' + d.getDate()
else
day = d.getDate();
var formattedDate = m + "/" + day + "/" + d.getFullYear();
var hours = (d.getHours() < 10) ? "0" + d.getHours() : d.getHours();
var minutes = (d.getMinutes() < 10) ? "0" + d.getMinutes() : d.getMinutes();
var formattedTime = hours + ":" + minutes + ":" + d.getSeconds();
formattedDate = formattedDate + " " + formattedTime;
return formattedDate;
}
You also can use the JavaScript library moment.js, which comes in handy when you plan do deal with different localized formats and perform other operations with dates values:
function getMismatch(id) {
$.getJSON("Main.aspx?Callback=GetMismatch",
{ MismatchId: id },
function (result) {
$("#AuthMerchId").text(result.AuthorizationMerchantId);
$("#SttlMerchId").text(result.SettlementMerchantId);
$("#CreateDate").text(moment(result.AppendDts).format("L"));
$("#ExpireDate").text(moment(result.ExpiresDts).format("L"));
$("#LastUpdate").text(moment(result.LastUpdateDts).format("L"));
$("#LastUpdatedBy").text(result.LastUpdateNt);
$("#ProcessIn").text(result.ProcessIn);
}
);
return false;
}
Setting up localization is as easy as adding configuration files (you get them at momentjs.com) to your project and configuring the language:
moment.lang('de');
Check up the date ISO standard; kind of like this:
yyyy.MM.ddThh:mm
It becomes 2008.11.20T22:18.
This is frustrating. My solution was to parse out the "/ and /" from the value generated by ASP.NET's JavaScriptSerializer so that, though JSON may not have a date literal, it still gets interpreted by the browser as a date, which is what all I really want:{"myDate":Date(123456789)}
Custom JavaScriptConverter for DateTime?
I must emphasize the accuracy of Roy Tinker's comment. This is not legal JSON. It's a dirty, dirty hack on the server to remove the issue before it becomes a problem for JavaScript. It will choke a JSON parser. I used it for getting off the ground, but I do not use this any more. However, I still feel the best answer lies with changing how the server formats the date, for example, ISO as mentioned elsewhere.
A late post, but for those who searched this post.
Imagine this:
[Authorize(Roles = "Administrator")]
[Authorize(Roles = "Director")]
[Authorize(Roles = "Human Resources")]
[HttpGet]
public ActionResult GetUserData(string UserIdGuidKey)
{
if (UserIdGuidKey!= null)
{
var guidUserId = new Guid(UserIdGuidKey);
var memuser = Membership.GetUser(guidUserId);
var profileuser = Profile.GetUserProfile(memuser.UserName);
var list = new {
UserName = memuser.UserName,
Email = memuser.Email ,
IsApproved = memuser.IsApproved.ToString() ,
IsLockedOut = memuser.IsLockedOut.ToString() ,
LastLockoutDate = memuser.LastLockoutDate.ToString() ,
CreationDate = memuser.CreationDate.ToString() ,
LastLoginDate = memuser.LastLoginDate.ToString() ,
LastActivityDate = memuser.LastActivityDate.ToString() ,
LastPasswordChangedDate = memuser.LastPasswordChangedDate.ToString() ,
IsOnline = memuser.IsOnline.ToString() ,
FirstName = profileuser.FirstName ,
LastName = profileuser.LastName ,
NickName = profileuser.NickName ,
BirthDate = profileuser.BirthDate.ToString() ,
};
return Json(list, JsonRequestBehavior.AllowGet);
}
return Redirect("Index");
}
As you can see, I'm utilizing C# 3.0's feature for creating the "Auto" Generics. It's a bit lazy, but I like it and it works.
Just a note: Profile is a custom class I've created for my web application project.
FYI, for anyone using Python on the server side: datetime.datetime().ctime() returns a string that is natively parsable by "new Date()". That is, if you create a new datetime.datetime instance (such as with datetime.datetime.now), the string can be included in the JSON string, and then that string can be passed as the first argument to the Date constructor. I haven't yet found any exceptions, but I haven't tested it too rigorously, either.
Mootools solution:
new Date(Date(result.AppendDts)).format('%x')
Requires mootools-more. Tested using mootools-1.2.3.1-more on Firefox 3.6.3 and IE 7.0.5730.13
var obj = eval('(' + "{Date: \/Date(1278903921551)\/}".replace(/\/Date\((\d+)\)\//gi, "new Date($1)") + ')');
var dateValue = obj["Date"];
Add the jQuery UI plugin in your page:
function DateFormate(dateConvert) {
return $.datepicker.formatDate("dd/MM/yyyy", eval('new ' + dateConvert.slice(1, -1)));
};
What if .NET returns...
return DateTime.Now.ToString("u"); //"2013-09-17 15:18:53Z"
And then in JavaScript...
var x = new Date("2013-09-17 15:18:53Z");
I'm taking my first crack at Ajax with jQuery. I'm getting my data onto my page, but I'm having some trouble with the JSON data that is returned for Date data types. Basically, I'm getting a string back that looks like this:
/Date(1224043200000)/
From someone totally new to JSON - How do I format this to a short date format? Should this be handled somewhere in the jQuery code? I've tried the jQuery.UI.datepicker plugin using $.datepicker.formatDate() without any success.
FYI: Here's the solution I came up with using a combination of the answers here:
function getMismatch(id) {
$.getJSON("Main.aspx?Callback=GetMismatch",
{ MismatchId: id },
function (result) {
$("#AuthMerchId").text(result.AuthorizationMerchantId);
$("#SttlMerchId").text(result.SettlementMerchantId);
$("#CreateDate").text(formatJSONDate(Date(result.AppendDts)));
$("#ExpireDate").text(formatJSONDate(Date(result.ExpiresDts)));
$("#LastUpdate").text(formatJSONDate(Date(result.LastUpdateDts)));
$("#LastUpdatedBy").text(result.LastUpdateNt);
$("#ProcessIn").text(result.ProcessIn);
}
);
return false;
}
function formatJSONDate(jsonDate) {
var newDate = dateFormat(jsonDate, "mm/dd/yyyy");
return newDate;
}
This solution got my object from the callback method and displayed the dates on the page properly using the date format library.
eval() is not necessary. This will work fine:
var date = new Date(parseInt(jsonDate.substr(6)));
The substr() function takes out the /Date( part, and the parseInt() function gets the integer and ignores the )/ at the end. The resulting number is passed into the Date constructor.
I have intentionally left out the radix (the 2nd argument to parseInt); see my comment below.
Also, I completely agree with Rory's comment: ISO-8601 dates are preferred over this old format - so this format generally shouldn't be used for new development.
For ISO-8601 formatted JSON dates, just pass the string into the Date constructor:
var date = new Date(jsonDate); //no ugly parsing needed; full timezone support
You can use this to get a date from JSON:
var date = eval(jsonDate.replace(/\/Date\((\d+)\)\//gi, "new Date($1)"));
And then you can use a JavaScript Date Format script (1.2 KB when minified and gzipped) to display it as you want.
For those using Newtonsoft Json.NET, read up on how to do it via Native JSON in IE8, Firefox 3.5 plus Json.NET.
Also the documentation on changing the format of dates written by Json.NET is useful:
Serializing Dates with Json.NET
For those that are too lazy, here are the quick steps. As JSON has a loose DateTime implementation, you need to use the IsoDateTimeConverter(). Note that since Json.NET 4.5 the default date format is ISO so the code below isn't needed.
string jsonText = JsonConvert.SerializeObject(p, new IsoDateTimeConverter());
The JSON will come through as
"fieldName": "2009-04-12T20:44:55"
Finally, some JavaScript to convert the ISO date to a JavaScript date:
function isoDateReviver(value) {
if (typeof value === 'string') {
var a = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)(?:([\+-])(\d{2})\:(\d{2}))?Z?$/.exec(value);
if (a) {
var utcMilliseconds = Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4], +a[5], +a[6]);
return new Date(utcMilliseconds);
}
}
return value;
}
I used it like this
$("<span />").text(isoDateReviver(item.fieldName).toLocaleString()).appendTo("#" + divName);
The original example:
/Date(1224043200000)/
does not reflect the formatting used by WCF when sending dates via WCF REST using the built-in JSON serialization. (at least on .NET 3.5, SP1)
I found the answer here helpful, but a slight edit to the regex is required, as it appears that the timezone GMT offset is being appended onto the number returned (since 1970) in WCF JSON.
In a WCF service I have:
[OperationContract]
[WebInvoke(
RequestFormat = WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json,
BodyStyle = WebMessageBodyStyle.WrappedRequest
)]
ApptVisitLinkInfo GetCurrentLinkInfo( int appointmentsId );
ApptVisitLinkInfo is defined simply:
public class ApptVisitLinkInfo {
string Field1 { get; set; }
DateTime Field2 { get; set; }
...
}
When "Field2" is returned as Json from the service the value is:
/Date(1224043200000-0600)/
Notice the timezone offset included as part of the value.
The modified regex:
/\/Date\((.*?)\)\//gi
It's slightly more eager and grabs everything between the parens, not just the first number. The resulting time sinze 1970, plus timezone offset can all be fed into the eval to get a date object.
The resulting line of JavaScript for the replace is:
replace(/\/Date\((.*?)\)\//gi, "new Date($1)");
Don't repeat yourself - automate date conversion using $.parseJSON()
Answers to your post provide manual date conversion to JavaScript dates. I've extended jQuery's $.parseJSON() just a little bit, so it's able to automatically parse dates when you instruct it to. It processes ASP.NET formatted dates (/Date(12348721342)/) as well as ISO formatted dates (2010-01-01T12.34.56.789Z) that are supported by native JSON functions in browsers (and libraries like json2.js).
Anyway. If you don't want to repeat your date conversion code over and over again I suggest you read this blog post and get the code that will make your life a little easier.
Click here to check the Demo
JavaScript/jQuery
var = MyDate_String_Value = "/Date(1224043200000)/"
var value = new Date
(
parseInt(MyDate_String_Value.replace(/(^.*\()|([+-].*$)/g, ''))
);
var dat = value.getMonth() +
1 +
"/" +
value.getDate() +
"/" +
value.getFullYear();
Result - "10/15/2008"
If you say in JavaScript,
var thedate = new Date(1224043200000);
alert(thedate);
you will see that it's the correct date, and you can use that anywhere in JavaScript code with any framework.
Updated
We have an internal UI library that has to cope with both Microsoft's ASP.NET built-in JSON format, like /Date(msecs)/, asked about here originally, and most JSON's date format including JSON.NET's, like 2014-06-22T00:00:00.0. In addition we need to cope with oldIE's inability to cope with anything but 3 decimal places.
We first detect what kind of date we're consuming, parse it into a normal JavaScript Date object, then format that out.
1) Detect Microsoft Date format
// Handling of Microsoft AJAX Dates, formatted like '/Date(01238329348239)/'
function looksLikeMSDate(s) {
return /^\/Date\(/.test(s);
}
2) Detect ISO date format
var isoDateRegex = /^(\d\d\d\d)-(\d\d)-(\d\d)T(\d\d):(\d\d):(\d\d)(\.\d\d?\d?)?([\+-]\d\d:\d\d|Z)?$/;
function looksLikeIsoDate(s) {
return isoDateRegex.test(s);
}
3) Parse MS date format:
function parseMSDate(s) {
// Jump forward past the /Date(, parseInt handles the rest
return new Date(parseInt(s.substr(6)));
}
4) Parse ISO date format.
We do at least have a way to be sure that we're dealing with standard ISO dates or ISO dates modified to always have three millisecond places (see above), so the code is different depending on the environment.
4a) Parse standard ISO Date format, cope with oldIE's issues:
function parseIsoDate(s) {
var m = isoDateRegex.exec(s);
// Is this UTC, offset, or undefined? Treat undefined as UTC.
if (m.length == 7 || // Just the y-m-dTh:m:s, no ms, no tz offset - assume UTC
(m.length > 7 && (
!m[7] || // Array came back length 9 with undefined for 7 and 8
m[7].charAt(0) != '.' || // ms portion, no tz offset, or no ms portion, Z
!m[8] || // ms portion, no tz offset
m[8] == 'Z'))) { // ms portion and Z
// JavaScript's weirdo date handling expects just the months to be 0-based, as in 0-11, not 1-12 - the rest are as you expect in dates.
var d = new Date(Date.UTC(m[1], m[2]-1, m[3], m[4], m[5], m[6]));
} else {
// local
var d = new Date(m[1], m[2]-1, m[3], m[4], m[5], m[6]);
}
return d;
}
4b) Parse ISO format with a fixed three millisecond decimal places - much easier:
function parseIsoDate(s) {
return new Date(s);
}
5) Format it:
function hasTime(d) {
return !!(d.getUTCHours() || d.getUTCMinutes() || d.getUTCSeconds());
}
function zeroFill(n) {
if ((n + '').length == 1)
return '0' + n;
return n;
}
function formatDate(d) {
if (hasTime(d)) {
var s = (d.getMonth() + 1) + '/' + d.getDate() + '/' + d.getFullYear();
s += ' ' + d.getHours() + ':' + zeroFill(d.getMinutes()) + ':' + zeroFill(d.getSeconds());
} else {
var s = (d.getMonth() + 1) + '/' + d.getDate() + '/' + d.getFullYear();
}
return s;
}
6) Tie it all together:
function parseDate(s) {
var d;
if (looksLikeMSDate(s))
d = parseMSDate(s);
else if (looksLikeIsoDate(s))
d = parseIsoDate(s);
else
return null;
return formatDate(d);
}
The below old answer is useful for tying this date formatting into jQuery's own JSON parsing so you get Date objects instead of strings, or if you're still stuck in jQuery <1.5 somehow.
Old Answer
If you're using jQuery 1.4's Ajax function with ASP.NET MVC, you can turn all DateTime properties into Date objects with:
// Once
jQuery.parseJSON = function(d) {return eval('(' + d + ')');};
$.ajax({
...
dataFilter: function(d) {
return d.replace(/"\\\/(Date\(-?\d+\))\\\/"/g, 'new $1');
},
...
});
In jQuery 1.5 you can avoid overriding the parseJSON method globally by using the converters option in the Ajax call.
http://api.jquery.com/jQuery.ajax/
Unfortunately you have to switch to the older eval route in order to get Dates to parse globally in-place - otherwise you need to convert them on a more case-by-case basis post-parse.
There is no built in date type in JSON. This looks like the number of seconds / milliseconds from some epoch. If you know the epoch you can create the date by adding on the right amount of time.
I also had to search for a solution to this problem and eventually I came across moment.js which is a nice library that can parse this date format and many more.
var d = moment(yourdatestring)
It saved some headache for me so I thought I'd share it with you. :)
You can find some more info about it here: http://momentjs.com/
I ended up adding the "characters into Panos's regular expression to get rid of the ones generated by the Microsoft serializer for when writing objects into an inline script:
So if you have a property in your C# code-behind that's something like
protected string JsonObject { get { return jsSerialiser.Serialize(_myObject); }}
And in your aspx you have
<script type="text/javascript">
var myObject = '<%= JsonObject %>';
</script>
You'd get something like
var myObject = '{"StartDate":"\/Date(1255131630400)\/"}';
Notice the double quotes.
To get this into a form that eval will correctly deserialize, I used:
myObject = myObject.replace(/"\/Date\((\d+)\)\/"/g, 'new Date($1)');
I use Prototype and to use it I added
String.prototype.evalJSONWithDates = function() {
var jsonWithDates = this.replace(/"\/Date\((\d+)\)\/"/g, 'new Date($1)');
return jsonWithDates.evalJSON(true);
}
In jQuery 1.5, as long as you have json2.js to cover for older browsers, you can deserialize all dates coming from Ajax as follows:
(function () {
var DATE_START = "/Date(";
var DATE_START_LENGTH = DATE_START.length;
function isDateString(x) {
return typeof x === "string" && x.startsWith(DATE_START);
}
function deserializeDateString(dateString) {
var dateOffsetByLocalTime = new Date(parseInt(dateString.substr(DATE_START_LENGTH)));
var utcDate = new Date(dateOffsetByLocalTime.getTime() - dateOffsetByLocalTime.getTimezoneOffset() * 60 * 1000);
return utcDate;
}
function convertJSONDates(key, value) {
if (isDateString(value)) {
return deserializeDateString(value);
}
return value;
}
window.jQuery.ajaxSetup({
converters: {
"text json": function(data) {
return window.JSON.parse(data, convertJSONDates);
}
}
});
}());
I included logic that assumes you send all dates from the server as UTC (which you should); the consumer then gets a JavaScript Date object that has the proper ticks value to reflect this. That is, calling getUTCHours(), etc. on the date will return the same value as it did on the server, and calling getHours() will return the value in the user's local timezone as determined by their browser.
This does not take into account WCF format with timezone offsets, though that would be relatively easy to add.
Using the jQuery UI datepicker - really only makes sense if you're already including jQuery UI:
$.datepicker.formatDate('MM d, yy', new Date(parseInt('/Date(1224043200000)/'.substr(6))));
output:
October 15, 2008
Don't over-think this. Like we've done for decades, pass a numeric offset from the de-facto standard epoch of 1 Jan 1970 midnight GMT/UTC/&c in number of seconds (or milliseconds) since this epoch. JavaScript likes it, Java likes it, C likes it, and the Internet likes it.
Everyone of these answers has one thing in common: they all store dates as a single value (usually a string).
Another option is to take advantage of the inherent structure of JSON, and represent a date as list of numbers:
{ "name":"Nick",
"birthdate":[1968,6,9] }
Of course, you would have to make sure both ends of the conversation agree on the format (year, month, day), and which fields are meant to be dates,... but it has the advantage of completely avoiding the issue of date-to-string conversion. It's all numbers -- no strings at all. Also, using the order: year, month, day also allows proper sorting by date.
Just thinking outside the box here -- a JSON date doesn't have to be stored as a string.
Another bonus to doing it this way is that you can easily (and efficiently) select all records for a given year or month by leveraging the way CouchDB handles queries on array values.
Posting in awesome thread:
var d = new Date(parseInt('/Date(1224043200000)/'.slice(6, -2)));
alert('' + (1 + d.getMonth()) + '/' + d.getDate() + '/' + d.getFullYear().toString().slice(-2));
Just to add another approach here, the "ticks approach" that WCF takes is prone to problems with timezones if you're not extremely careful such as described here and in other places. So I'm now using the ISO 8601 format that both .NET & JavaScript duly support that includes timezone offsets. Below are the details:
In WCF/.NET:
Where CreationDate is a System.DateTime; ToString("o") is using .NET's Round-trip format specifier that generates an ISO 8601-compliant date string
new MyInfo {
CreationDate = r.CreationDate.ToString("o"),
};
In JavaScript
Just after retrieving the JSON I go fixup the dates to be JavaSript Date objects using the Date constructor which accepts an ISO 8601 date string...
$.getJSON(
"MyRestService.svc/myinfo",
function (data) {
$.each(data.myinfos, function (r) {
this.CreatedOn = new Date(this.CreationDate);
});
// Now each myinfo object in the myinfos collection has a CreatedOn field that is a real JavaScript date (with timezone intact).
alert(data.myinfos[0].CreationDate.toLocaleString());
}
)
Once you have a JavaScript date you can use all the convenient and reliable Date methods like toDateString, toLocaleString, etc.
var newDate = dateFormat(jsonDate, "mm/dd/yyyy");
Is there another option without using the jQuery library?
This may can also help you.
function ToJavaScriptDate(value) { //To Parse Date from the Returned Parsed Date
var pattern = /Date\(([^)]+)\)/;
var results = pattern.exec(value);
var dt = new Date(parseFloat(results[1]));
return (dt.getMonth() + 1) + "/" + dt.getDate() + "/" + dt.getFullYear();
}
I get the date like this:
"/Date(1276290000000+0300)/"
In some examples the date is in slightly different formats:
"/Date(12762900000000300)/"
"Date(1276290000000-0300)"
etc.
So I came up with the following RegExp:
/\/+Date\(([\d+]+)\)\/+/
and the final code is:
var myDate = new Date(parseInt(jsonWcfDate.replace(/\/+Date\(([\d+-]+)\)\/+/, '$1')));
Hope it helps.
Update:
I found this link from Microsoft:
How do I Serialize Dates with JSON?
This seems like the one we are all looking for.
Below is a pretty simple solution for parsing JSON dates. Use the below functions as per your requirement. You just need to pass the JSON format Date fetched as a parameter to the functions below:
function JSONDate(dateStr) {
var m, day;
jsonDate = dateStr;
var d = new Date(parseInt(jsonDate.substr(6)));
m = d.getMonth() + 1;
if (m < 10)
m = '0' + m
if (d.getDate() < 10)
day = '0' + d.getDate()
else
day = d.getDate();
return (m + '/' + day + '/' + d.getFullYear())
}
function JSONDateWithTime(dateStr) {
jsonDate = dateStr;
var d = new Date(parseInt(jsonDate.substr(6)));
var m, day;
m = d.getMonth() + 1;
if (m < 10)
m = '0' + m
if (d.getDate() < 10)
day = '0' + d.getDate()
else
day = d.getDate();
var formattedDate = m + "/" + day + "/" + d.getFullYear();
var hours = (d.getHours() < 10) ? "0" + d.getHours() : d.getHours();
var minutes = (d.getMinutes() < 10) ? "0" + d.getMinutes() : d.getMinutes();
var formattedTime = hours + ":" + minutes + ":" + d.getSeconds();
formattedDate = formattedDate + " " + formattedTime;
return formattedDate;
}
You also can use the JavaScript library moment.js, which comes in handy when you plan do deal with different localized formats and perform other operations with dates values:
function getMismatch(id) {
$.getJSON("Main.aspx?Callback=GetMismatch",
{ MismatchId: id },
function (result) {
$("#AuthMerchId").text(result.AuthorizationMerchantId);
$("#SttlMerchId").text(result.SettlementMerchantId);
$("#CreateDate").text(moment(result.AppendDts).format("L"));
$("#ExpireDate").text(moment(result.ExpiresDts).format("L"));
$("#LastUpdate").text(moment(result.LastUpdateDts).format("L"));
$("#LastUpdatedBy").text(result.LastUpdateNt);
$("#ProcessIn").text(result.ProcessIn);
}
);
return false;
}
Setting up localization is as easy as adding configuration files (you get them at momentjs.com) to your project and configuring the language:
moment.lang('de');
Check up the date ISO standard; kind of like this:
yyyy.MM.ddThh:mm
It becomes 2008.11.20T22:18.
This is frustrating. My solution was to parse out the "/ and /" from the value generated by ASP.NET's JavaScriptSerializer so that, though JSON may not have a date literal, it still gets interpreted by the browser as a date, which is what all I really want:{"myDate":Date(123456789)}
Custom JavaScriptConverter for DateTime?
I must emphasize the accuracy of Roy Tinker's comment. This is not legal JSON. It's a dirty, dirty hack on the server to remove the issue before it becomes a problem for JavaScript. It will choke a JSON parser. I used it for getting off the ground, but I do not use this any more. However, I still feel the best answer lies with changing how the server formats the date, for example, ISO as mentioned elsewhere.
A late post, but for those who searched this post.
Imagine this:
[Authorize(Roles = "Administrator")]
[Authorize(Roles = "Director")]
[Authorize(Roles = "Human Resources")]
[HttpGet]
public ActionResult GetUserData(string UserIdGuidKey)
{
if (UserIdGuidKey!= null)
{
var guidUserId = new Guid(UserIdGuidKey);
var memuser = Membership.GetUser(guidUserId);
var profileuser = Profile.GetUserProfile(memuser.UserName);
var list = new {
UserName = memuser.UserName,
Email = memuser.Email ,
IsApproved = memuser.IsApproved.ToString() ,
IsLockedOut = memuser.IsLockedOut.ToString() ,
LastLockoutDate = memuser.LastLockoutDate.ToString() ,
CreationDate = memuser.CreationDate.ToString() ,
LastLoginDate = memuser.LastLoginDate.ToString() ,
LastActivityDate = memuser.LastActivityDate.ToString() ,
LastPasswordChangedDate = memuser.LastPasswordChangedDate.ToString() ,
IsOnline = memuser.IsOnline.ToString() ,
FirstName = profileuser.FirstName ,
LastName = profileuser.LastName ,
NickName = profileuser.NickName ,
BirthDate = profileuser.BirthDate.ToString() ,
};
return Json(list, JsonRequestBehavior.AllowGet);
}
return Redirect("Index");
}
As you can see, I'm utilizing C# 3.0's feature for creating the "Auto" Generics. It's a bit lazy, but I like it and it works.
Just a note: Profile is a custom class I've created for my web application project.
FYI, for anyone using Python on the server side: datetime.datetime().ctime() returns a string that is natively parsable by "new Date()". That is, if you create a new datetime.datetime instance (such as with datetime.datetime.now), the string can be included in the JSON string, and then that string can be passed as the first argument to the Date constructor. I haven't yet found any exceptions, but I haven't tested it too rigorously, either.
Mootools solution:
new Date(Date(result.AppendDts)).format('%x')
Requires mootools-more. Tested using mootools-1.2.3.1-more on Firefox 3.6.3 and IE 7.0.5730.13
var obj = eval('(' + "{Date: \/Date(1278903921551)\/}".replace(/\/Date\((\d+)\)\//gi, "new Date($1)") + ')');
var dateValue = obj["Date"];
Add the jQuery UI plugin in your page:
function DateFormate(dateConvert) {
return $.datepicker.formatDate("dd/MM/yyyy", eval('new ' + dateConvert.slice(1, -1)));
};
What if .NET returns...
return DateTime.Now.ToString("u"); //"2013-09-17 15:18:53Z"
And then in JavaScript...
var x = new Date("2013-09-17 15:18:53Z");
I have date from the date picker which I am accessing as -
var transdate = $j("input[name='enterdate']").val();
resulting in transdate = "6/22/2015"
I need to test if the entered date is between two dates which are defined as
startdate = '2015-02-01' and enddate = '2015-07-30'
How do I convert the transdate in yyyy-mm-dd format in the following code -
if ((new Date('transdate')>= startdate ) && (new Date('transdate') <= enddate )) {
alert("correct date entered");
}
Moment.js is a small handy library for dates that makes this easy.
moment('6/22/2015', 'M/D/YYYY')
.isBetween('2015-02-01', '2015-07-30'); // => true
Note that only the first (US format) date string needed an explicit format string supplied.
Moment can be useful for the parsing alone, eg. even if not using isBetween:
var transdate = moment('6/22/2015', 'M/D/YYYY').toDate();
var startdate = moment('2015-02-01').toDate();
var enddate = moment('2015-07-30').toDate();
transdate >= startdate && transdate <= enddate // => true
The string is not in the only format defined to be handled by the Date object. That means you have to parse it (with regular expressions or String#split or whatever), or use a library like MomentJS that will parse it for you. Once you've parsed the dates, you can compare them with < or >, etc.
Do not rely on Date to parse strings it's not defined to parse. You will run into implementations or locales where it doesn't work.
"6/22/2015" is trivial to parse with a regular expression:
var rex = /^(\d+)\/(\d+)\/(\d+)$/;
var match = rex.exec(transdate);
var dt = match ? new Date(+match[3], +match[1] - 1, +match[2]) : null;
That uses the Date constructor that accepts the parts of the date as individual numeric arguments (year, month, day). The + converts strings to numbers. The [x] are capture groups from the regex. You have to subtract one from the month because months start with 0 in JavaScript.
Similar questions have been asked many, many times but I can't seem to find a duplicate. Given the unreliability of the Date constructor to parse strings, the simplest solution is to parse the string yourself:
function parseMDY(s) {
var b = s.split(/\D/);
return new Date(b[2], b[0]-1, b[1]);
}
Here is the JSFIDDLE of you output.
Moment.js will give you good flexibility in coding.
Dont forget to add jquery and moment.js in your html
var transdate="6/22/2014";
var convertStringToValidDate = new Date(transdate);
$(document).ready(function(){
$("#selectedDate").text(transdate);
$("#validDate").text(convertStringToValidDate);
converttoformat = moment(convertStringToValidDate).format("YYYY-MM-DD");
$("#converttoyyyymmdd").text(converttoformat);
if(moment(converttoformat).isBetween('2015-02-01', '2015-07-30')){
$("#result").text("Date lies in between");
}
else{
$("#result").text("Date is out of scope");
}
});
I noticed Date.Parse can't handle only 2 digits dates.
Say I have this
mm/dd/yy = 7/11/20
Date parse will think it is = 7/11/1920. Can you set it to use the year two thousand? Like it's kinda weird I got the jquery u.i date picker and if you type in 7/11/20 it will figure out 2020.
So it would be nice if Date.parse could keep up I rather have them both not know what is going on or both know what is going on then have one that knows and one that does not know.
Not that I'm aware of. But you can always adjust the year:
YourDate="7/11/20";
DateObj=new Date(YourDate.replace(/(\d\d)$/,"20$1"));
alert(DateObj);
This code in action.
Edit: The following code will handle both full and short years:
YourDate="7/11/2020";
DateObj=new Date(YourDate.replace(/\/(\d\d)$/,"/20$1"));
alert(DateObj);
This code in action.
So your question is whether you can change the way Date.parse works so that low-numbered two-digit dates are interpreted as dates after the year 2000?
Yes, it can be done, simply shadow Date.parse with your own parse function.
// don't do this!
Date.parse = function (str) { /* your parse routine here */ }
Of course, it's generally a very bad idea to shadow properties (including 'methods' aka function properties) of host objects, because it will cause incorrect behavior in other scripts that expect those properties to work a certain way.
It's also a bad idea to use two digit dates, but that might be beyond your control. If it's not beyond your control, I'd advise to just forget 2-digit dates and use the full year value instead.
Here is my solution:
function parseDate(stringValue)
{
var date = new Date(stringValue);
if (!isNaN(date.getTime()))
{
// if they typed the year in full then the parsed date will have the correct year,
// if they only typed 2 digits, add 100 years to it so that it gets translated to this century
if (stringValue.indexOf(date.getFullYear()) == -1)
{
date.setFullYear(date.getFullYear() + 100);
}
return date;
}
else
{
return null;
}
}
How about this?
var date = '7/11/20';
var idx = date.lastIndexOf('/') + 1;
date = date.substr(0,idx) + '20' + date.substr(idx);
var result = Date.parse(date);
alert(result);
or this version that will test for a YYYY format first.
var date = '7/11/2020';
var idx = date.lastIndexOf('/') + 1;
if(date.substr(idx).length < 4) {
date = date.substr(0,idx) + '20' + date.substr(idx);
}
var result = Date.parse(date);
alert(new Date(result));
My date objects in JavaScript are always represented by UTC +2 because of where I am located. Hence like this
Mon Sep 28 10:00:00 UTC+0200 2009
Problem is doing a JSON.stringify converts the above date to
2009-09-28T08:00:00Z (notice 2 hours missing i.e. 8 instead of 10)
What I need is for the date and time to be honoured but it's not, hence it should be
2009-09-28T10:00:00Z (this is how it should be)
Basically I use this:
var jsonData = JSON.stringify(jsonObject);
I tried passing a replacer parameter (second parameter on stringify) but the problem is that the value has already been processed.
I also tried using toString() and toUTCString() on the date object, but these don't give me what I want either..
Can anyone help me?
Recently I have run into the same issue. And it was resolved using the following code:
x = new Date();
let hoursDiff = x.getHours() - x.getTimezoneOffset() / 60;
let minutesDiff = (x.getHours() - x.getTimezoneOffset()) % 60;
x.setHours(hoursDiff);
x.setMinutes(minutesDiff);
JSON uses the Date.prototype.toISOString function which does not represent local time -- it represents time in unmodified UTC -- if you look at your date output you can see you're at UTC+2 hours, which is why the JSON string changes by two hours, but if this allows the same time to be represented correctly across multiple time zones.
date.toJSON() prints the UTC-Date into a String formatted (So adds the offset with it when converts it to JSON format).
date = new Date();
new Date(date.getTime() - (date.getTimezoneOffset() * 60000)).toJSON();
Just for the record, remember that the last "Z" in "2009-09-28T08:00:00Z" means that the time is indeed in UTC.
See http://en.wikipedia.org/wiki/ISO_8601 for details.
Out-of-the-box solution to force JSON.stringify ignore timezones:
Pure javascript (based on Anatoliy answer):
// Before: JSON.stringify apply timezone offset
const date = new Date();
let string = JSON.stringify(date);
console.log(string);
// After: JSON.stringify keeps date as-is!
Date.prototype.toJSON = function(){
const hoursDiff = this.getHours() - this.getTimezoneOffset() / 60;
this.setHours(hoursDiff);
return this.toISOString();
};
string = JSON.stringify(date);
console.log(string);
Using moment + moment-timezone libraries:
const date = new Date();
let string = JSON.stringify(date);
console.log(string);
Date.prototype.toJSON = function(){
return moment(this).format("YYYY-MM-DDTHH:mm:ss:ms");;
};
string = JSON.stringify(date);
console.log(string);
<html>
<header>
<script src="https://momentjs.com/downloads/moment.min.js"></script>
<script src="https://momentjs.com/downloads/moment-timezone-with-data-10-year-range.min.js"></script>
</header>
</html>
Here is another answer (and personally I think it's more appropriate)
var currentDate = new Date();
currentDate = JSON.stringify(currentDate);
// Now currentDate is in a different format... oh gosh what do we do...
currentDate = new Date(JSON.parse(currentDate));
// Now currentDate is back to its original form :)
you can use moment.js to format with local time:
Date.prototype.toISOString = function () {
return moment(this).format("YYYY-MM-DDTHH:mm:ss");
};
I'm a little late but you can always overwrite the toJson function in case of a Date using Prototype like so:
Date.prototype.toJSON = function(){
return Util.getDateTimeString(this);
};
In my case, Util.getDateTimeString(this) return a string like this: "2017-01-19T00:00:00Z"
I run into this a bit working with legacy stuff where they only work on east coast US and don't store dates in UTC, it's all EST. I have to filter on the dates based on user input in the browser so must pass the date in local time in JSON format.
Just to elaborate on this solution already posted - this is what I use:
// Could be picked by user in date picker - local JS date
date = new Date();
// Create new Date from milliseconds of user input date (date.getTime() returns milliseconds)
// Subtract milliseconds that will be offset by toJSON before calling it
new Date(date.getTime() - (date.getTimezoneOffset() * 60000)).toJSON();
So my understanding is this will go ahead and subtract time (in milliseconds (hence 60000) from the starting date based on the timezone offset (returns minutes) - in anticipation for the addition of time toJSON() is going to add.
JavaScript normally convert local timezone to UTC .
date = new Date();
date.setMinutes(date.getMinutes()-date.getTimezoneOffset())
JSON.stringify(date)
Usually you want dates to be presented to each user in his own local time-
that is why we use GMT (UTC).
Use Date.parse(jsondatestring) to get the local time string,
unless you want your local time shown to each visitor.
In that case, use Anatoly's method.
Got around this issue by using the moment.js library (the non-timezone version).
var newMinDate = moment(datePicker.selectedDates[0]);
var newMaxDate = moment(datePicker.selectedDates[1]);
// Define the data to ask the server for
var dataToGet = {"ArduinoDeviceIdentifier":"Temperatures",
"StartDate":newMinDate.format('YYYY-MM-DD HH:mm'),
"EndDate":newMaxDate.format('YYYY-MM-DD HH:mm')
};
alert(JSON.stringify(dataToGet));
I was using the flatpickr.min.js library. The time of the resulting JSON object created matches the local time provided but the date picker.
Here is something really neat and simple (atleast I believe so :)) and requires no manipulation of date to be cloned or overloading any of browser's native functions like toJSON (reference: How to JSON stringify a javascript Date and preserve timezone, courtsy Shawson)
Pass a replacer function to JSON.stringify that stringifies stuff to your heart's content!!! This way you don't have to do hour and minute diffs or any other manipulations.
I have put in console.logs to see intermediate results so it is clear what is going on and how recursion is working. That reveals something worthy of notice: value param to replacer is already converted to ISO date format :). Use this[key] to work with original data.
var replacer = function(key, value)
{
var returnVal = value;
if(this[key] instanceof Date)
{
console.log("replacer called with key - ", key, " value - ", value, this[key]);
returnVal = this[key].toString();
/* Above line does not strictly speaking clone the date as in the cloned object
* it is a string in same format as the original but not a Date object. I tried
* multiple things but was unable to cause a Date object being created in the
* clone.
* Please Heeeeelp someone here!
returnVal = new Date(JSON.parse(JSON.stringify(this[key]))); //OR
returnVal = new Date(this[key]); //OR
returnVal = this[key]; //careful, returning original obj so may have potential side effect
*/
}
console.log("returning value: ", returnVal);
/* if undefined is returned, the key is not at all added to the new object(i.e. clone),
* so return null. null !== undefined but both are falsy and can be used as such*/
return this[key] === undefined ? null : returnVal;
};
ab = {prop1: "p1", prop2: [1, "str2", {p1: "p1inner", p2: undefined, p3: null, p4date: new Date()}]};
var abstr = JSON.stringify(ab, replacer);
var abcloned = JSON.parse(abstr);
console.log("ab is: ", ab);
console.log("abcloned is: ", abcloned);
/* abcloned is:
* {
"prop1": "p1",
"prop2": [
1,
"str2",
{
"p1": "p1inner",
"p2": null,
"p3": null,
"p4date": "Tue Jun 11 2019 18:47:50 GMT+0530 (India Standard Time)"
}
]
}
Note p4date is string not Date object but format and timezone are completely preserved.
*/
I ran into the same problem.
The way I resolvet it was:
var currentTime = new Date();
Console.log(currentTime); //Return: Wed Sep 15 13:52:09 GMT-05:00 2021
Console.log(JSON.stringify(currentTime)); //Return: "2021-09-15T18:52:09.891Z"
var currentTimeFixed = new Date(currentTime.setHours(currentTime.getHours() - (currentTime.getUTCHours() - currentTime.getHours())));
Console.log(JSON.stringify(currentTimeFixed)); //Return: "2021-09-15T13:52:09.891Z"
I wrote the following code blog where it makes service calls.. it will try to serializable the json in every post submission, it will format to local date it again.
protected async post(endPoint: string, data, panelName?: string, hasSuccessMessage: boolean = false): Promise<Observable<any>> {
const options = this.InitHeader(true);
const url: string = this._baseUrl + endPoint;
Date.prototype.toJSON = function () {
return moment(this).format("YYYY-MM-DDThh:mm:00.000Z");;
};
return await this._http.post(url, data, options).pipe(map(response => {
return this.Map<any>(response, null);
}));
}
All boils down to if your server backend is timezone-agnostic or not.
If it is not, then you need to assume that timezone of server is the same as client, or transfer information about client's timezone and include that also into calculations.
a PostgreSQL backend based example:
select '2009-09-28T08:00:00Z'::timestamp -> '2009-09-28 08:00:00' (wrong for 10am)
select '2009-09-28T08:00:00Z'::timestamptz -> '2009-09-28 10:00:00+02'
select '2009-09-28T08:00:00Z'::timestamptz::timestamp -> '2009-09-28 10:00:00'
The last one is probably what you want to use in database, if you are not willing properly implement timezone logic.
Instead of toJSON, you can use format function which always gives the correct date and time + GMT
This is the most robust display option. It takes a string of tokens
and replaces them with their corresponding values.
I tried this in angular 8 :
create Model :
export class Model { YourDate: string | Date; }
in your component
model : Model;
model.YourDate = new Date();
send Date to your API for saving
When loading your data from API you will make this :
model.YourDate = new Date(model.YourDate+"Z");
you will get your date correctly with your time zone.
In this case I think you need transform the date to UNIX timestamp
timestamp = testDate.getTime();
strJson = JSON.stringify(timestamp);
After that you can re use it to create a date object and format it. Example with javascript and toLocaleDateString ( https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/Date/toLocaleDateString )
newDateObject = new Date(JSON.parse(strJson));
newDateObject = newDateObject.toLocalDateStrin([
"fr-FR",
]);
If you use stringify to use AJAX, now it's not useful. You just need to send timestamp and get it in your script:
$newDateObject = new \DateTime();
$newDateObject->setTimestamp(round($timestamp/1000));
Be aware that getTime() will return a time in milliseconds and the PHP function setTimestamp take time in seconds. It's why you need to divide by 1000 and round.
In Angular place the following in index.js script section:
setTimeout(function (){
Date.prototype.toJSON = function(){
return new Date(this).toLocaleDateString("en-US") + " "+new Date(this).toLocaleTimeString();
}},1000);