1

I'm writing a MVC 5 web application. Into this, I have multiple lists that I propagate and manage through javascript and jquery (one dataset, dependent select controls, and adding ajax callbacks would complicate it unnecessarily.)

The issue I have is: I have a hidden for field formatted to ISO 8601. I run into issues when I display the date in the user's local time, I get a shifted date.

So if the date were stated as: 01-01-2009 (in iso 8601 format: 2009-01-01), the user sees: 12-31-2008.

When I parse the date I'm using:

this.date = new Date(Date.parse(originalString));
/* ^- Date.parse is giving me a number. */

To display the text of the date I am using:

admin.date.toLocaleDateString().Concat(...

Do I need to do any sort of patch-up to adjust things to the proper time-zone? The date, when using console.log(admin.date); shows the original 2009-01-01

I'm thinking there's some parameter I'm not specifying correctly in the toLocaleDateString, but my familiarity level with it is low.

Edit: The goal is to prevent the date shift. All we store is the date, the time aspect is dropped. We have multiple time-zones posting to this database, and the goal is: We use the date of the person who posted it, time dropped. Were the date May 01, 2015, I want anyone who sees that date to see May 01, 2015, the 'toLocaleDateString' is merely a means to get it to appear format correct for their region. So someone who views dates as yyyy-mm-dd will see it properly.

  • Well, if you omit hours/minutes, they default to midnight. And midnights, as we know, happen 24 times in a day (because timezones)... Your local midnight for 1st of January might have been a midnight on 31st of December etc. – Robert Rossmann Jun 08 '15 at 19:46
  • just read the API for that method: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toLocaleDateString – pherris Jun 08 '15 at 19:48
  • Depending on the version of the standard that's implemented, partial ISO 8601 date strings will default to be considered in the UTC timezone. [From ES 5.1 - *The value of an absent time zone offset is “**Z**”.*](http://www.ecma-international.org/ecma-262/5.1/#sec-15.9.1.15) The upcoming ES 6 standard has so far changed that to the user's local timezone. – Jonathan Lonowski Jun 08 '15 at 19:49
  • 2
    I recently ran into this issue and solved it by using [Moment.js](http://momentjs.com/) for JavaScript date logic. – rink.attendant.6 Jun 08 '15 at 19:49
  • Related: [javascript Date.parse](http://stackoverflow.com/questions/2587345/javascript-date-parse) and [different result for yyyy-mm-dd and yyyy/mm/dd in javascript when passed to “new Date”](http://stackoverflow.com/questions/30199130/different-result-for-yyyy-mm-dd-and-yyyy-mm-dd-in-javascript-when-passed-to-new) – Jonathan Lonowski Jun 08 '15 at 19:53
  • Well I appreciate, and get that the time shift occurs due to design, but the question I have is: how do I prevent it? – Allen Clark Copeland Jr Jun 08 '15 at 20:08

1 Answers1

1

Based on the documentation for Date.parse:

The Date.parse() method parses a string representation of a date, and returns the number of milliseconds since January 1, 1970, 00:00:00 UTC.

You are getting back the epoch time in UTC for your parsed date string hence why the date is off for local times. So, you would need to know the time difference between the local time and UTC which Date.getTimezoneOffset provides (in minutes) in order to set the correct date for the local time:

> var date = new Date(Date.parse('2009-01-01'));
undefined
> date;
Wed Dec 31 2008 19:00:00 GMT-0500 (EST)
> date.getTimezoneOffset();
300
> date.setMinutes(date.getTimezoneOffset());
1230786000000
> date;
Thu Jan 01 2009 00:00:00 GMT-0500 (EST)

One thing to note though is:

...the offset is positive if the local timezone is behind UTC and negative if it is ahead.

So you might need to take care for locales where the value is negative if this applies to your application. If so maybe just omitting negative values would be enough since the date should be the same if a locale's timezone is ahead of midnight UTC.

EDIT: To compensate for possible issues with daylight savings time:

> var dateVals = String.prototype.split.call('2009-01-01', '-');
undefined
> var date = new Date(dateVals[0], dateVals[1] - 1, dateVals[2]);
undefined
> date
Thu Jan 01 2009 00:00:00 GMT-0500 (EST)
Jason Cust
  • 10,743
  • 2
  • 33
  • 45
  • I ended up with: `this.date = new Date(date); var offsetDate = new Date(86400000); offsetDate.setMinutes(offsetDate.getTimezoneOffset()); this.date = new Date(this.date.getTime() + offsetDate.getTime() - 86400000);` That should handle negative timezones, right? – Allen Clark Copeland Jr Jun 08 '15 at 20:50
  • Well, it doesn't appear to, working on it. My initial solution had the timezone worked in, but in setting my own timezone to -840 minutes I get back to where I started. – Allen Clark Copeland Jr Jun 08 '15 at 20:58
  • I think you can just ignore negative values since it should only be times behind UTC (the positive values) that would have the wrong date. – Jason Cust Jun 08 '15 at 20:59
  • Sorry to be the bearer of bad news, but this approach is flawed. It's seen quite commonly, but it's *always* wrong. You cannot change the `Date` object's behavior by shifting the timestamp by the amount of the offset. It will *still* be influenced by the local time zone. All you've done is given it a different moment in time. These effects are noticeable near daylight saving time transitions. – Matt Johnson-Pint Jun 08 '15 at 20:59
  • 1
    Indeed, it doesn't appear to be a solution, in fiddling with the time settings on my system, it appears to fluctuate between 'working and not working' which means it doesn't work. – Allen Clark Copeland Jr Jun 08 '15 at 21:02
  • @MattJohnson Agreed on the daylight savings issue (which is a monster and would recommend only a library for that but the OP's question is for a date (not a time). To compensate for the daylight savings issue I would set the time at 2AM UTC and then apply only the positive offset values to ensure the date is the same across the globe. – Jason Cust Jun 08 '15 at 21:03
  • Not sure how 2AM UTC would be any safer. There are time zones that transition near that point. The `Date` object always has a time component (it's misnamed, should be `DateTime`). When you call `getTimezoneOffset`, the specific moment in time you call that on is important, and will change near the DST transitions. – Matt Johnson-Pint Jun 08 '15 at 21:06
  • The safer and simpler ways to deal with this are as seen [in this answer](http://stackoverflow.com/a/24717734/634824). – Matt Johnson-Pint Jun 08 '15 at 21:06
  • @MattJohnson I chose 2AM out of hand but maybe 3 or 4 would provide more cushion. Moment.js would be useful but it's a hefty library if this is the only use for it. – Jason Cust Jun 08 '15 at 21:13
  • There is a common approach of using Noon (12 PM) to avoid DST transitions, but that only works when you're talking about Noon *local time*. If you're parsing as local time (slashes instead of dashes in js), Noon keeps you from stepping on time zones like Brazil where the transition occurs right at Midnight. This technique doesn't work when you're parsing as UTC and the time zone is variable. – Matt Johnson-Pint Jun 08 '15 at 21:16
  • @AlexanderMorou I made an update that will create a new date object that is always set to the local time. – Jason Cust Jun 08 '15 at 23:19
  • moment.js solved the issue, but I'm not very happy with the result. Three thousand lines to solve something that should be simple, is a little unsettling. – Allen Clark Copeland Jr Jun 09 '15 at 13:19
  • @AlexanderMorou agreed that moment.js is a bit of overkill for this. Just wondering if the second solution I posted would work as it should always create a date set to the local timezone. – Jason Cust Jun 10 '15 at 14:01
  • I decided the issue wasn't worth getting hung up on. The development priority of getting a date to format a certain way is below moving the project forward. So I decided to cheat: provide three sets of data, 1. The Date the server receives (its raw value, understood by the MVC deserializer) 2. The Ticks of the dates for filtering/ordering 3. the pre-formatted date used to concat the details of the item for display to the user (there's additional data that goes with the date.) – Allen Clark Copeland Jr Jun 10 '15 at 15:25
  • @Alexander Morou `..it appears to fluctuate between 'working and not working' which means it doesn't work.` LoL. :D – SherylHohman Apr 14 '18 at 04:33