448

I have a web page with three dropdowns for day, month and year. If I use the JavaScript Date constructor that takes numbers, then I get a Date object for my current timezone:

new Date(xiYear, xiMonth, xiDate)

Give the correct date, but it thinks that date is GMT+01:00 due to daylight savings time.

The problem here is that I then pass this Date to an Ajax method and when the date is deserialised on the server it has been converted to GMT and so lost an hour which moves the day back by one. Now I could just pass the day, month, and year individually into the Ajax method, but it seems that there ought to be a better way.

The accepted answer pointed me in the right direction, however just using setUTCHours() by itself changed:

Apr 5th 00:00 GMT+01:00 

to

Apr 4th 23:00 GMT+01:00

I then also had to set the UTC date, month and year to end up with

Apr 5th 01:00 GMT+01:00

which is what I wanted.

Dan
  • 6,650
  • 6
  • 29
  • 41
  • 12
    If the accepted answer pointed you in the right direction but didn't answer your question, I would argue it shouldn't be the accepted answer. The answer should answer the question asked. – T.W.R. Cole Aug 29 '18 at 18:16

26 Answers26

507

using .setUTCHours() it would be possible to actually set dates in UTC-time, which would allow you to use UTC-times throughout the system.

You cannot set it using UTC in the constructor though, unless you specify a date-string.

Using new Date(Date.UTC(year, month, day, hour, minute, second)) you can create a Date-object from a specific UTC time.

meager
  • 209,754
  • 38
  • 307
  • 315
jishi
  • 22,747
  • 6
  • 45
  • 73
  • 105
    The "new Date(Date.UTC(...))" syntax allows you to create a date which is *equivalent* to a UTC date in terms of the point in time that it represents, but it is not the same - it has a different (non UTC) time zone. – Anthony Dec 06 '11 at 16:22
  • 56
    Keep in mind that when using "Date" the "month"-value has a range from 0-11 (not 1-12). I kept getting a timezone-offset of 2h (while it should have been 1h) and it took me hours to find out that the reason was a wrong month. – Select0r Feb 28 '12 at 14:17
  • 4
    This answer is great. But i am using a library [datepicker ui] that is using new Date at many places. All I want is to set the UTC timezone and every date is as per new timezone. I am surprised Javascript doesn't have nothing for this. – Sanjeev Kumar Dangi Aug 16 '12 at 06:48
  • 2
    Nothing stops you from taking in a "time zone" as a separate parameter and handle it yourself. A Date object i js is always represented as "local" time, you can just choose to set it from a different timezone, but toString() will still show it as the appropriate local time. – jishi Aug 17 '12 at 08:20
  • 1
    @SanjeevKumarDangi JavaScript has all it needs for this, [datepicker ui] is using it wrong (it is working with local time only, so it suffers from DST bugs depending on local timezone and the time you set on the date object). Most date pickers you'll encounter have the same problems. – Tiberiu-Ionuț Stan Jan 08 '13 at 14:38
  • 7
    @jishi—Date objects are based on a UTC time value, not local time. However, the default *Date.prototype.toString* method will **display** local time values. – RobG May 27 '13 at 05:54
  • 1
    @RobG And the constructor and individual setters are also based on the local time. How the inner representation of the time is handled doesn't matter in this case. He wanted to create a Date object FROM a UTC time (probably from a server variable), so I don't see what you're getting at. – jishi May 27 '13 at 09:13
  • 7
    @Anthony—"*but it is not the same time*" is not correct. It represents exactly the same moment in time, the only difference is the timezone offset. – RobG Jan 20 '15 at 23:25
  • 1
    @jishi—I'm getting at "*A Date object i js is always represented as "local" time*", which is wrong. The internal time value of a Date object is UTC, per the [*language specification*](http://ecma-international.org/ecma-262/5.1/#sec-15.9.1.1). The timezone offset is used to display a local time. – RobG Jan 20 '15 at 23:27
  • If you need Date Object with given date string https://stackoverflow.com/questions/948532/how-do-you-convert-a-javascript-date-to-utc/52220773#52220773 – keemor Sep 07 '18 at 10:57
209
var d = new Date(xiYear, xiMonth, xiDate);
d.setTime( d.getTime() + d.getTimezoneOffset()*60*1000 );

This answer is tailored specifically to the original question, and will not give the answer you necessarily expect. In particular, some people will want to subtract the timezone offset instead of add it. Remember though that the whole point of this solution is to hack javascript's date object for a particular deserialization, not to be correct in all cases.

T.W.R. Cole
  • 3,832
  • 1
  • 16
  • 26
  • 1
    you could just do `*60000` instead of `*60*1000` :) – gthmb Feb 26 '14 at 09:11
  • 62
    @gthmb of course, but I feel that `*60*1000` is clearer in this case; in other words, it is fairly self-evident why it is there. – T.W.R. Cole Mar 03 '14 at 23:37
  • 22
    This almost works for me, except I have to use - (minus) instead of + (plus) to get the right time for my time zone. – Wytze Mar 17 '14 at 11:38
  • 1
    this was definitely the most elegant/sexiest answer to an ugly problem. thank you! – Ryan Vettese May 13 '14 at 16:21
  • 3
    Yeah, as others have pointed out - I think there is a mistake in this answer. Should be minus not plus. – UpTheCreek Jun 12 '14 at 09:28
  • 3
    According to https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getTimezoneOffset the value returned by getTimezoneOffset is signed according to the actual offset in your locale at the time you call the function, including taking DST into account, so I don't understand why you'd need to subtract it. – T.W.R. Cole Aug 04 '14 at 17:26
  • 17
    If you add the timezoneOffset to the date object, its value as formatted in the local timezone will look like the correct value in UTC, but it will still have the original timezone offset (and some representations like "ISOString" will actually show it). So depending on how you then serialize the date object, JS might apply the timezone offset *again*, giving you the wrong answer. I believe this is responsible for the confusion in these comments between +/-. Anyway, my downvote is for this fact and also for the "in most cases you get what you expect". – metamatt Aug 26 '14 at 17:55
  • Example of what I'm talking about, from a computer in California, on 2014-August-26 in the PST time zone: `d = new Date(2014, 07, 26, 11)` gives me `Tue Aug 26 2014 11:00:00 GMT-0700 (PDT)`, `d.getTimezoneOffset()` returns `420`, so the transformation suggested in this answer turns the local representation of `d` into `Tue Aug 26 2014 18:00:00 GMT-0700 (PDT)` (7 hours later, accurately showing that 11 am PDT is 6 pm GMT). Except for that pesky "-0700 (PDT)" suffix showing the 420-sec timezone offset is still there, and: `d.toISOString()` returns `2014-08-27T01:00:00.000Z`. – metamatt Aug 26 '14 at 17:59
  • 1
    @metamatt You are correct. I've removed my opinions from the answer and made it clear that this is not the right answer for everyone interested in the original question. – T.W.R. Cole Aug 26 '14 at 18:53
  • 1
    d.setTime( d.getTime() + Math.abs(d.getTimezoneOffset())*60*1000 ); – Justin Alexander Jan 08 '15 at 08:36
  • To get a value equivalent to `new Date(Date.UTC(y, m,d));` you actually need to substract timezone, not add it. – Nux Mar 10 '15 at 10:54
  • 1
    This answer is flawed. It fails if the conversion moves the date across a timezone i.e. the date is right next to the daylight saving boundary. If inputDate is Sun Apr 01 2007 00:00:00 GMT+1300 (New Zealand Daylight Time) converted by new Date(inputDate.getTime() + (inputDate.getTimezoneOffset() * 60000)) returns Sat Mar 31 2007 11:00:00 GMT+1300 (New Zealand Daylight Time). Use @monsterclub's createDateAsUTC and convertDateToUTC instead. – RockResolve Jun 27 '16 at 22:46
  • @RockResolve I'm not really inclined to try and steal monsterclub's answer wholesale; I've upvoted it, though – T.W.R. Cole Jul 06 '16 at 16:32
183

I believe you need the createDateAsUTC function (please compare with convertDateToUTC)

function createDateAsUTC(date) {
    return new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds()));
}

function convertDateToUTC(date) { 
    return new Date(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds()); 
}
falsarella
  • 11,640
  • 8
  • 65
  • 104
monsterclub
  • 1,871
  • 1
  • 10
  • 2
  • 39
    I am amazed about his answer clarity and helpfulness. Did not know that working with Javascript dates was such a nightmare until today :S – will824 Feb 12 '14 at 17:00
  • Mind explaining the difference between the two? The first converts `date` into UTC timezone, but the second seems to be doing nothing useful? (returns same date as `date`) – Jonathan Lin Aug 05 '15 at 05:53
  • 4
    I get it now: The first returns the date in the UTC timezone, with the literal date values of the local time. The second returns the date in the local timezone, but with the UTC literal date values. – Jonathan Lin Aug 05 '15 at 07:22
  • 8
    This approach is one implementation of a pattern called "epoch shifting", which is intended to move the epoch (that is UTC based) to one that is shifted by the current time zone offset. Unfortunately, even though this is commonly seen, this approach is flawed. JavaScript's `Date` object will always reflect the UTC-based unix epoch, and the *local* time zone. The symptom is apparent when you call `toString` on the resulting date object and still see the local time zone, even though you expected it to be in UTC. – Matt Johnson-Pint Jan 23 '16 at 23:29
  • 2
    It also can cause errors in the time values, near the daylight saving time transitions of the local time zone. In short, epoch shifting (via any implementation) does not work with the JavaScript `Date` object. Another way to see this here is that `Date.UTC` expects UTC-based values, and you're feeding it local time values, and vise-versa with the `Date` constructor. – Matt Johnson-Pint Jan 23 '16 at 23:30
  • These functions helped me with converting to the Unix timestamp on the client side, so thanks to the answerer – Manny Fleurmond Mar 21 '16 at 10:18
  • dude I was looking for the answer to this for like 5 hours thanks so much! – btm1 Apr 02 '16 at 16:24
  • @MattJohnson I believe this method is perfectly acceptable as long as you understand that whatever dates you're working with are always set to the environment's TZ. If you're wanting to store the dates in UTC, you'll have to have clear separations between epoch-shifted / non-shifted dates and handle accordingly. – AlbertEngelB Nov 30 '17 at 18:08
  • @AlbertEngelB - what in your opinion are the best ways to store dates in UTC, avoiding the epoch-shifting method? – obaylis Jun 12 '19 at 14:25
123

Simply Set the Time Zone and Get Back According

new Date().toLocaleString("en-US", {timeZone: "America/New_York"})

Other Time-zones are as Following

var world_timezones =
[
    'Europe/Andorra',
    'Asia/Dubai',
    'Asia/Kabul',
    'Europe/Tirane',
    'Asia/Yerevan',
    'Antarctica/Casey',
    'Antarctica/Davis',
    'Antarctica/DumontDUrville', 
    'Antarctica/Mawson',
    'Antarctica/Palmer',
    'Antarctica/Rothera',
    'Antarctica/Syowa',
    'Antarctica/Troll',
    'Antarctica/Vostok',
    'America/Argentina/Buenos_Aires',
    'America/Argentina/Cordoba',
    'America/Argentina/Salta',
    'America/Argentina/Jujuy',
    'America/Argentina/Tucuman',
    'America/Argentina/Catamarca',
    'America/Argentina/La_Rioja',
    'America/Argentina/San_Juan',
    'America/Argentina/Mendoza',
    'America/Argentina/San_Luis',
    'America/Argentina/Rio_Gallegos',
    'America/Argentina/Ushuaia',
    'Pacific/Pago_Pago',
    'Europe/Vienna',
    'Australia/Lord_Howe',
    'Antarctica/Macquarie',
    'Australia/Hobart',
    'Australia/Currie',
    'Australia/Melbourne',
    'Australia/Sydney',
    'Australia/Broken_Hill',
    'Australia/Brisbane',
    'Australia/Lindeman',
    'Australia/Adelaide',
    'Australia/Darwin',
    'Australia/Perth',
    'Australia/Eucla',
    'Asia/Baku',
    'America/Barbados',
    'Asia/Dhaka',
    'Europe/Brussels',
    'Europe/Sofia',
    'Atlantic/Bermuda',
    'Asia/Brunei',
    'America/La_Paz',
    'America/Noronha',
    'America/Belem',
    'America/Fortaleza',
    'America/Recife',
    'America/Araguaina',
    'America/Maceio',
    'America/Bahia',
    'America/Sao_Paulo',
    'America/Campo_Grande',
    'America/Cuiaba',
    'America/Santarem',
    'America/Porto_Velho',
    'America/Boa_Vista',
    'America/Manaus',
    'America/Eirunepe',
    'America/Rio_Branco',
    'America/Nassau',
    'Asia/Thimphu',
    'Europe/Minsk',
    'America/Belize',
    'America/St_Johns',
    'America/Halifax',
    'America/Glace_Bay',
    'America/Moncton',
    'America/Goose_Bay',
    'America/Blanc-Sablon',
    'America/Toronto',
    'America/Nipigon',
    'America/Thunder_Bay',
    'America/Iqaluit',
    'America/Pangnirtung',
    'America/Atikokan',
    'America/Winnipeg',
    'America/Rainy_River',
    'America/Resolute',
    'America/Rankin_Inlet',
    'America/Regina',
    'America/Swift_Current',
    'America/Edmonton',
    'America/Cambridge_Bay',
    'America/Yellowknife',
    'America/Inuvik',
    'America/Creston',
    'America/Dawson_Creek',
    'America/Fort_Nelson',
    'America/Vancouver',
    'America/Whitehorse',
    'America/Dawson',
    'Indian/Cocos',
    'Europe/Zurich',
    'Africa/Abidjan',
    'Pacific/Rarotonga',
    'America/Santiago',
    'America/Punta_Arenas',
    'Pacific/Easter',
    'Asia/Shanghai',
    'Asia/Urumqi',
    'America/Bogota',
    'America/Costa_Rica',
    'America/Havana',
    'Atlantic/Cape_Verde',
    'America/Curacao',
    'Indian/Christmas',
    'Asia/Nicosia',
    'Asia/Famagusta',
    'Europe/Prague',
    'Europe/Berlin',
    'Europe/Copenhagen',
    'America/Santo_Domingo',
    'Africa/Algiers',
    'America/Guayaquil',
    'Pacific/Galapagos',
    'Europe/Tallinn',
    'Africa/Cairo',
    'Africa/El_Aaiun',
    'Europe/Madrid',
    'Africa/Ceuta',
    'Atlantic/Canary',
    'Europe/Helsinki',
    'Pacific/Fiji',
    'Atlantic/Stanley',
    'Pacific/Chuuk',
    'Pacific/Pohnpei',
    'Pacific/Kosrae',
    'Atlantic/Faroe',
    'Europe/Paris',
    'Europe/London',
    'Asia/Tbilisi',
    'America/Cayenne',
    'Africa/Accra',
    'Europe/Gibraltar',
    'America/Godthab',
    'America/Danmarkshavn',
    'America/Scoresbysund',
    'America/Thule',
    'Europe/Athens',
    'Atlantic/South_Georgia',
    'America/Guatemala',
    'Pacific/Guam',
    'Africa/Bissau',
    'America/Guyana',
    'Asia/Hong_Kong',
    'America/Tegucigalpa',
    'America/Port-au-Prince',
    'Europe/Budapest',
    'Asia/Jakarta',
    'Asia/Pontianak',
    'Asia/Makassar',
    'Asia/Jayapura',
    'Europe/Dublin',
    'Asia/Jerusalem',
    'Asia/Kolkata',
    'Indian/Chagos',
    'Asia/Baghdad',
    'Asia/Tehran',
    'Atlantic/Reykjavik',
    'Europe/Rome',
    'America/Jamaica',
    'Asia/Amman',
    'Asia/Tokyo',
    'Africa/Nairobi',
    'Asia/Bishkek',
    'Pacific/Tarawa',
    'Pacific/Enderbury',
    'Pacific/Kiritimati',
    'Asia/Pyongyang',
    'Asia/Seoul',
    'Asia/Almaty',
    'Asia/Qyzylorda',
    'Asia/Qostanay', 
    'Asia/Aqtobe',
    'Asia/Aqtau',
    'Asia/Atyrau',
    'Asia/Oral',
    'Asia/Beirut',
    'Asia/Colombo',
    'Africa/Monrovia',
    'Europe/Vilnius',
    'Europe/Luxembourg',
    'Europe/Riga',
    'Africa/Tripoli',
    'Africa/Casablanca',
    'Europe/Monaco',
    'Europe/Chisinau',
    'Pacific/Majuro',
    'Pacific/Kwajalein',
    'Asia/Yangon',
    'Asia/Ulaanbaatar',
    'Asia/Hovd',
    'Asia/Choibalsan',
    'Asia/Macau',
    'America/Martinique',
    'Europe/Malta',
    'Indian/Mauritius',
    'Indian/Maldives',
    'America/Mexico_City',
    'America/Cancun',
    'America/Merida',
    'America/Monterrey',
    'America/Matamoros',
    'America/Mazatlan',
    'America/Chihuahua',
    'America/Ojinaga',
    'America/Hermosillo',
    'America/Tijuana',
    'America/Bahia_Banderas',
    'Asia/Kuala_Lumpur',
    'Asia/Kuching',
    'Africa/Maputo',
    'Africa/Windhoek',
    'Pacific/Noumea',
    'Pacific/Norfolk',
    'Africa/Lagos',
    'America/Managua',
    'Europe/Amsterdam',
    'Europe/Oslo',
    'Asia/Kathmandu',
    'Pacific/Nauru',
    'Pacific/Niue',
    'Pacific/Auckland',
    'Pacific/Chatham',
    'America/Panama',
    'America/Lima',
    'Pacific/Tahiti',
    'Pacific/Marquesas',
    'Pacific/Gambier',
    'Pacific/Port_Moresby',
    'Pacific/Bougainville',
    'Asia/Manila',
    'Asia/Karachi',
    'Europe/Warsaw',
    'America/Miquelon',
    'Pacific/Pitcairn',
    'America/Puerto_Rico',
    'Asia/Gaza',
    'Asia/Hebron',
    'Europe/Lisbon',
    'Atlantic/Madeira',
    'Atlantic/Azores',
    'Pacific/Palau',
    'America/Asuncion',
    'Asia/Qatar',
    'Indian/Reunion',
    'Europe/Bucharest',
    'Europe/Belgrade',
    'Europe/Kaliningrad',
    'Europe/Moscow',
    'Europe/Simferopol',
    'Europe/Kirov',
    'Europe/Astrakhan',
    'Europe/Volgograd',
    'Europe/Saratov',
    'Europe/Ulyanovsk',
    'Europe/Samara',
    'Asia/Yekaterinburg',
    'Asia/Omsk',
    'Asia/Novosibirsk',
    'Asia/Barnaul',
    'Asia/Tomsk',
    'Asia/Novokuznetsk',
    'Asia/Krasnoyarsk',
    'Asia/Irkutsk',
    'Asia/Chita',
    'Asia/Yakutsk',
    'Asia/Khandyga',
    'Asia/Vladivostok',
    'Asia/Ust-Nera',
    'Asia/Magadan',
    'Asia/Sakhalin',
    'Asia/Srednekolymsk',
    'Asia/Kamchatka',
    'Asia/Anadyr',
    'Asia/Riyadh',
    'Pacific/Guadalcanal',
    'Indian/Mahe',
    'Africa/Khartoum',
    'Europe/Stockholm',
    'Asia/Singapore',
    'America/Paramaribo',
    'Africa/Juba',
    'Africa/Sao_Tome',
    'America/El_Salvador',
    'Asia/Damascus',
    'America/Grand_Turk',
    'Africa/Ndjamena',
    'Indian/Kerguelen',
    'Asia/Bangkok',
    'Asia/Dushanbe',
    'Pacific/Fakaofo',
    'Asia/Dili',
    'Asia/Ashgabat',
    'Africa/Tunis',
    'Pacific/Tongatapu',
    'Europe/Istanbul',
    'America/Port_of_Spain',
    'Pacific/Funafuti',
    'Asia/Taipei',
    'Europe/Kiev',
    'Europe/Uzhgorod',
    'Europe/Zaporozhye',
    'Pacific/Wake',
    'America/New_York',
    'America/Detroit',
    'America/Kentucky/Louisville',
    'America/Kentucky/Monticello',
    'America/Indiana/Indianapolis',
    'America/Indiana/Vincennes',
    'America/Indiana/Winamac',
    'America/Indiana/Marengo',
    'America/Indiana/Petersburg',
    'America/Indiana/Vevay',
    'America/Chicago',
    'America/Indiana/Tell_City',
    'America/Indiana/Knox',
    'America/Menominee',
    'America/North_Dakota/Center',
    'America/North_Dakota/New_Salem',
    'America/North_Dakota/Beulah',
    'America/Denver',
    'America/Boise',
    'America/Phoenix',
    'America/Los_Angeles',
    'America/Anchorage',
    'America/Juneau',
    'America/Sitka',
    'America/Metlakatla',
    'America/Yakutat',
    'America/Nome',
    'America/Adak',
    'Pacific/Honolulu',
    'America/Montevideo',
    'Asia/Samarkand',
    'Asia/Tashkent',
    'America/Caracas',
    'Asia/Ho_Chi_Minh',
    'Pacific/Efate',
    'Pacific/Wallis',
    'Pacific/Apia',
    'Africa/Johannesburg'
];
Matee Gojra
  • 3,005
  • 2
  • 23
  • 30
  • 18
    This should be way up at the top – Eugene Feb 22 '19 at 19:06
  • 2
    Except be aware that this doesn't work in some browsers. Eg. IE11. – Paul LeBeau Apr 15 '19 at 16:56
  • **Error in IE Console:** _Option value 'AMERICA/NEW_YORK' for 'timeZone' is outside of valid range. Expected: ['UTC']_ @OloghoCyrilPaul – Matee Gojra May 10 '19 at 04:35
  • 2
    Very easy, very elegant. You can find here a list with all the timezones https://stackoverflow.com/questions/38399465/how-to-get-list-of-all-timezones-in-javascript . For UTC pick London timezone. – EPurpl3 Aug 21 '19 at 07:54
  • 2
    None of those values are "timezones", they are [*IANA timezone database*](https://www.iana.org/time-zones) representative locations for places that have the same historic local timezone and daylight saving changes. – RobG Oct 12 '19 at 10:23
  • @EPurpl3—that is bad advice. Firstly, a stackoverflow answer is not an authority, IANA representative locations should be sought from the IANA timezone database. Secondly, they are not timezones, they're representative locations for places that share the same historic timezone offset changes. Lastly, London observes daylight saving so 'Europe/London' will differ from UTC from the end of March to the end of October every year that daylight saving is observed. – RobG Oct 12 '19 at 10:24
  • @RobG Yes, you are right. The list includes Daylight Saving Time hours, which can be useful for some. I needed the hour with DST so it was perfect for me. Here is a full list of hours with and without DST. https://en.wikipedia.org/wiki/List_of_tz_database_time_zones . Soon if you use London as UTC there wont be a DST anymore because on 27 Oct 2019 Europe will scrap DST for ever so it's going to be only 1 hour for London. My answer was a bit ahead of it's time but soon it will be perfect for everybody, not just for some :). https://www.timeanddate.com/news/time/europe-may-scrap-dst.html – EPurpl3 Oct 15 '19 at 07:05
28

I don't believe this is possible - there is no ability to set the timezone on a Date object after it is created.

And in a way this makes sense - conceptually (if perhaps not in implementation); per http://en.wikipedia.org/wiki/Unix_timestamp (emphasis mine):

Unix time, or POSIX time, is a system for describing instants in time, defined as the number of seconds elapsed since midnight Coordinated Universal Time (UTC) of Thursday, January 1, 1970.

Once you've constructed one it will represent a certain point in "real" time. The time zone is only relevant when you want to convert that abstract time point into a human-readable string.

Thus it makes sense you would only be able to change the actual time the Date represents in the constructor. Sadly it seems that there is no way to pass in an explicit timezone - and the constructor you are calling (arguably correctly) translates your "local" time variables into GMT when it stores them canonically - so there is no way to use the int, int, int constructor for GMT times.

On the plus side, it's trivial to just use the constructor that takes a String instead. You don't even have to convert the numeric month into a String (on Firefox at least), so I was hoping a naive implementation would work. However, after trying it out it works successfully in Firefox, Chrome, and Opera but fails in Konqueror ("Invalid Date") , Safari ("Invalid Date") and IE ("NaN"). I suppose you'd just have a lookup array to convert the month to a string, like so:

var months = [ '', 'January', 'February', ..., 'December'];

function createGMTDate(xiYear, xiMonth, xiDate) {
   return new Date(months[xiMonth] + ' ' + xiDate + ', ' + xiYear + ' 00:00:00 GMT');
}
Andrzej Doyle
  • 97,637
  • 30
  • 185
  • 225
  • 6
    If there's no way to "set the timezone on a Date object after it is created", are you implying that there's a way to set the timezone on a Date object *as* it is created? It doesn't look like a js date is "thin wrapper around a number of seconds since the Epoch" - it looks like it's that count of seconds, plus a time zone. – Anthony Dec 06 '11 at 16:20
  • 1
    @Anthony, It can only use the client's timezone. Javascript can do local to utc and back but there is no access to a timezone database. It cannot, for example, tell you the Time in Mexico City when you're in San Diego. – Samuel Danielson Apr 28 '16 at 22:50
22

I know this is old but if it helps you could use moment and moment time zone. If you haven't seen them take a look.

http://momentjs.com/timezone/

http://momentjs.com/

two really handy time manipulation libraries.

Phillip Senn
  • 43,069
  • 83
  • 242
  • 359
ChewOnThis_Trident
  • 1,875
  • 1
  • 17
  • 21
18

If you want to deal with the slightly different, but related, problem of creating a Javascript Date object from year, month, day, ..., including timezone – that is, if you want to parse a string into a Date – then you apparently have to do an infuriatingly complicated dance:

// parseISO8601String : string -> Date
// Parse an ISO-8601 date, including possible timezone,
// into a Javascript Date object.
//
// Test strings: parseISO8601String(x).toISOString()
// "2013-01-31T12:34"              -> "2013-01-31T12:34:00.000Z"
// "2013-01-31T12:34:56"           -> "2013-01-31T12:34:56.000Z"
// "2013-01-31T12:34:56.78"        -> "2013-01-31T12:34:56.780Z"
// "2013-01-31T12:34:56.78+0100"   -> "2013-01-31T11:34:56.780Z"
// "2013-01-31T12:34:56.78+0530"   -> "2013-01-31T07:04:56.780Z"
// "2013-01-31T12:34:56.78-0330"   -> "2013-01-31T16:04:56.780Z"
// "2013-01-31T12:34:56-0330"      -> "2013-01-31T16:04:56.000Z"
// "2013-01-31T12:34:56Z"          -> "2013-01-31T12:34:56.000Z"
function parseISO8601String(dateString) {
    var timebits = /^([0-9]{4})-([0-9]{2})-([0-9]{2})T([0-9]{2}):([0-9]{2})(?::([0-9]*)(\.[0-9]*)?)?(?:([+-])([0-9]{2})([0-9]{2}))?/;
    var m = timebits.exec(dateString);
    var resultDate;
    if (m) {
        var utcdate = Date.UTC(parseInt(m[1]),
                               parseInt(m[2])-1, // months are zero-offset (!)
                               parseInt(m[3]),
                               parseInt(m[4]), parseInt(m[5]), // hh:mm
                               (m[6] && parseInt(m[6]) || 0),  // optional seconds
                               (m[7] && parseFloat(m[7])*1000) || 0); // optional fraction
        // utcdate is milliseconds since the epoch
        if (m[9] && m[10]) {
            var offsetMinutes = parseInt(m[9]) * 60 + parseInt(m[10]);
            utcdate += (m[8] === '+' ? -1 : +1) * offsetMinutes * 60000;
        }
        resultDate = new Date(utcdate);
    } else {
        resultDate = null;
    }
    return resultDate;
}

That is, you create a 'UTC time' using the date without timezone (so you know what locale it's in, namely the UTC 'locale', and it's not defaulted to the local one), and then manually apply the indicated timezone offset.

Wouldn't it have been nice if someone had actually thought about the Javascript date object for more than, oooh, five minutes....

Norman Gray
  • 10,851
  • 2
  • 26
  • 50
  • 1
    thanks for the great function! the only thing i would change is add support for the colon in the timezone offset. var timebits = /^([0-9]{4})-([0-9]{2})-([0-9]{2})T([0-9]{2}):([0-9]{2})(?::([0-9]*)(\.[0-9]*)?)?(?:([+-])([0-9]{2}[:]?)([0-9]{2}))?/; – robnardo Nov 11 '13 at 22:01
  • 2
    They did think about it; unfortunately, the "they" was the Java language designers, as JS just copied Java's Date class over for its initial implementation. – Xanthir Aug 05 '16 at 21:32
  • @Xanthir Oooh, you're right, and I'd forgotten how awful the original Java Date object was; but at least Java deprecated it and moved on, something Javascript seems unable to do (it's a bizarre language, Javascript: rather cute, and not nearly as awful as it first appears to be). – Norman Gray Aug 06 '16 at 15:21
14
d = new Date();
utc = d.getTime() + (d.getTimezoneOffset() * 60000);
nd = new Date(utc + (3600000*offset));

offset value base on which location time zone you would like to set 
For India offset value +5.5,
New York offset value -4,
London offset value +1

for all location offset Wiki List of UTC time offsets

Vijay Lathiya
  • 825
  • 9
  • 12
8

getTimeZoneOffset is minus for UTC + z.

var d = new Date(xiYear, xiMonth, xiDate);
if(d.getTimezoneOffset() > 0){
    d.setTime( d.getTime() + d.getTimezoneOffset()*60*1000 );
}
rinjan
  • 530
  • 5
  • 18
8

This may help someone, put UTC at the end of what you pass in to the new constructor

At least in chrome you can say var date = new Date("2014-01-01 11:00:00 UTC")

Drew LeSueur
  • 16,653
  • 27
  • 85
  • 96
  • 1
    Returns "Invalid Date" on Safari – pmrotule Oct 18 '17 at 12:48
  • 1
    Replace ` UTC` with `+0000` (noticed that the space between 00 and UTC need to be removed) and this will work on both Firefox and Chrome. Not sure for Safari though.(Reference: https://stackoverflow.com/a/17545854/1273587) – cytsunny Jan 25 '19 at 05:49
8

One line solution

new Date(new Date(1422524805305).getTime() - 330*60*1000)

Instead of 1422524805305, use the timestamp in milliseconds Instead of 330, use your timezone offset in minutes wrt. GMT (eg India +5:30 is 5*60+30 = 330 minutes)

Vinay Vemula
  • 3,197
  • 1
  • 19
  • 23
  • 5
    This would be code run on the client, meaning the timezone is going to be different for your differently located users. This solution would require that everyone who needs it lives in the same timezone (yours). – Kevin Beal Jun 23 '15 at 19:26
  • @Kevin Beal in that case just use getTimezoneOffset – maximus Oct 06 '15 at 06:48
7
// My clock 2018-07-25, 00:26:00 (GMT+7)
let date = new Date(); // 2018-07-24:17:26:00 (Look like GMT+0)
const myTimeZone = 7; // my timeZone 
// my timeZone = 7h = 7 * 60 * 60 * 1000 (millisecond);
// 2018-07-24:17:26:00 = x (milliseconds)
// finally, time in milliseconds (GMT+7) = x + myTimezone 
date.setTime( date.getTime() + myTimeZone * 60 * 60 * 1000 );
// date.toISOString() = 2018-07-25, 00:26:00 (GMT+7)
Tuan Nguyen
  • 2,151
  • 15
  • 25
  • Explaining your code and how it solves the problem will raise the quality of your answer, and help learning users. – Nic3500 Jul 25 '18 at 00:55
5

The easiest way that I have found to get the correct date is using datejs.

http://www.datejs.com/

I get my dates via Ajax in this format as a string: '2016-01-12T00:00:00'

var yourDateString = '2016-01-12T00:00:00';
var yourDate = new Date(yourDateString);
console.log(yourDate);
if (yourDate.getTimezoneOffset() > 0){
    yourDate = new Date(yourDateString).addMinutes(yourDate.getTimezoneOffset());
}
console.log(yourDate);

Console will read:

Mon Jan 11 2016 19:00:00 GMT-0500 (Eastern Standard Time)

Tue Jan 12 2016 00:00:00 GMT-0500 (Eastern Standard Time)

https://jsfiddle.net/vp1ena7b/3/

The 'addMinutes' comes from datejs, you could probably do this in pure js on your own, but I already had datejs in my project so I found a way to use it to get the correct dates.

I thought that this might help someone...

Barry Franklin
  • 1,593
  • 1
  • 26
  • 42
  • Tried all the methods and this was the only one to get midnight which was what I was after! – SharpC May 11 '18 at 14:56
4

This code will return your Date object formatted with the browser timezone.

Date.prototype.timezone = function () {
    this.setHours(this.getHours() + (new Date().getTimezoneOffset() / 60));
    return this;
}

Edit:

To avoid to pollute the Date API, the above function can be transformed into a utility function. The function takes a Date object, and returns a mutated Date object.

function setTimeZone(date) {
    date.setHours(date.getHours() + (new Date().getTimezoneOffset() / 60));
    return date;
}
P.M
  • 2,280
  • 2
  • 35
  • 43
Marco Dal Zovo
  • 370
  • 2
  • 16
3

any mileage in

var d = new Date(xiYear, xiMonth, xiDate).toLocaleString();
meouw
  • 40,162
  • 10
  • 48
  • 67
  • This seems to do the trick for me (one time zone away from GMT), but since "locale" is not necessarily timezone related, I wouldn't rely on it. – Wytze Mar 17 '14 at 11:33
1

Best Solution I have seen from this came from

http://www.codingforums.com/archive/index.php/t-19663.html

Print Time Function

<script language="javascript" type="text/javascript">
//borrowed from echoecho
//http://www.echoecho.com/ubb/viewthread.php?tid=2362&pid=10482&#pid10482
workDate = new Date()
UTCDate = new Date()
UTCDate.setTime(workDate.getTime()+workDate.getTimezoneOffset()*60000)

function printTime(offset) {
    offset++;
    tempDate = new Date()
    tempDate.setTime(UTCDate.getTime()+3600000*(offset))
    timeValue = ((tempDate.getHours()<10) ? ("0"+tempDate.getHours()) : (""+tempDate.getHours()))
    timeValue += ((tempDate.getMinutes()<10) ? ("0"+tempDate.getMinutes()) : tempDate.getMinutes())
    timeValue += " hrs."
    return timeValue
    }
    var now = new Date()
    var seed = now.getTime() % 0xfffffff
    var same = rand(12)
</script>

Banff, Canada:
<script language="JavaScript">document.write(printTime("-7"))</script>

Full Code Example

<html>

<head>
<script language="javascript" type="text/javascript">
//borrowed from echoecho
//http://www.echoecho.com/ubb/viewthread.php?tid=2362&pid=10482&#pid10482
workDate = new Date()
UTCDate = new Date()
UTCDate.setTime(workDate.getTime()+workDate.getTimezoneOffset()*60000)

function printTime(offset) {
offset++;
tempDate = new Date()
tempDate.setTime(UTCDate.getTime()+3600000*(offset))
timeValue = ((tempDate.getHours()<10) ? ("0"+tempDate.getHours()) : (""+tempDate.getHours()))
timeValue += ((tempDate.getMinutes()<10) ? ("0"+tempDate.getMinutes()) : tempDate.getMinutes())
timeValue += " hrs."
return timeValue
}
var now = new Date()
var seed = now.getTime() % 0xfffffff
var same = rand(12)
</script>

</head>

<body>
Banff, Canada:
<script language="JavaScript">document.write(printTime("-7"))</script>
<br>
Michigan:
<script language="JavaScript">document.write(printTime("-5"))</script>
<br>
Greenwich, England(UTC):
<script language="JavaScript">document.write(printTime("-0"))</script>
<br>
Tokyo, Japan:
<script language="JavaScript">document.write(printTime("+9"))</script>
<br>
Berlin, Germany:
<script language="JavaScript">document.write(printTime("+1"))</script>

</body>
</html>
Jeffrey L. Roberts
  • 2,485
  • 5
  • 29
  • 54
  • Your example excludes Daylight Saving Time. CurrentTime: Fri Oct 04 2013 11:13:43 GMT-0700 (Pacific Daylight Time) UtcTime: Fri, 04 Oct 2013 18:13:43 GMT Banff, Canada: 1213 hrs. Michigan: 1413 hrs. Greenwich, England(UTC): 1913 hrs. Tokyo, Japan: 0413 hrs. Berlin, Germany: 2013 hrs. – Jeson Martajaya Oct 04 '13 at 18:15
1

GMT -03:00 Example

new Date(new Date()-3600*1000*3).toISOString();  // 2020-02-27T15:03:26.261Z

Or even

now  = new Date().getTime()-3600*1000*3; // 1582818380528
data = new Date(now).toISOString();      // 2020-02-27T15:03:26.261Z
Rafael Xavier
  • 671
  • 8
  • 8
1

You can use library to help to change time zone

moment-timezone

var moment = require("moment-timezone");
const today = new Date();
var timeGet = moment(today);
timeGet.tz("Asia/Karachi").format("ha z");

this can change your time zone of your region paste your region area and get real gmt+ resolve issue

For more details visit moment timezone official documentation

Matee Gojra
  • 3,005
  • 2
  • 23
  • 30
0

if you want to check the difference in a time between two dates, you can simply check if second timezone is lesser or greater from your first desired timezone and subtract or add a time.

  const currTimezone = new Date().getTimezoneOffset(); // your timezone
  const newDateTimezone = date.getTimezoneOffset(); // date with unknown timezone

  if (currTimezone !== newDateTimezone) {
    // and below you are checking if difference should be - or +. It depends on if unknown timezone is lesser or greater than yours
    const newTimezone = (currTimezone - newDateTimezone) * (currTimezone > newDateTimezone ? 1 : -1);
    date.setTime(date.getTime() + (newTimezone * 60 * 1000));
  }
Piosek
  • 170
  • 1
  • 9
0

I was having a similar problem with a date picker. My research led to a very simple solution, without any extra libraries or hardcoded multipliers.

Key info:

  1. ISO is the Javascript preferred date standard. Assume date utilities will likely return date values in that format.
    • My date picker displays the date in a localized format: mm/dd/yyyy

    • However, it returns the date value in the ISO format: yyyy-mm-dd

      //Select "08/12/2020" in Date Picker date_input 
      
      var input = $('#date_input').val();  //input: 2020-08-12
      
  1. Date.getTimezoneOffset() returns the offset in minutes.

Examples:

If you use the default returned date value without modifying the string format, the Date might not get set to your timezone. This can lead to unexpected results.

var input = $('#date_input').val();  //input: 2020-08-12
var date = new Date(input);          //This get interpreted as an ISO date, already in UTC
//date:                             Tue Aug 11 2020 20:00:00 GMT-0400 (Eastern Daylight Time)
//date.toUTCString():               Wed, 12 Aug 2020 00:00:00 GMT
//date.toLocaleDateString('en-US'):       8/11/2020

Using a different date string format than the ISO standard yyyy-mm-dd applies your timezone to the Date.

var date = new Date("08/12/2020");  //This gets interpreted as local timezone
//date:                             Wed Aug 12 2020 00:00:00 GMT-0400 (Eastern Daylight Time)
//date.toUTCString():               Wed, 12 Aug 2020 04:00:00 GMT
//date.toLocaleDateString('en-US'):       8/12/2020

Solution:

To apply your timezone to the format-agnostic Date without doing string manipulation, use Date.getTimezoneOffset() with Minutes. This works with either original date string format (i.e. UTC dates or localized dates). It provides a consistent result which can then be converted accurately to UTC for storage or interacting with other code.

var input = $('#date_input').val();
var date = new Date(input);
date.setMinutes(date.getMinutes() + date.getTimezoneOffset());
//date:                             Wed Aug 12 2020 00:00:00 GMT-0400 (Eastern Daylight Time)
//date.toUTCString():               Wed, 12 Aug 2020 04:00:00 GMT
//date.toLocaleDateString('en-US'):       8/12/2020
                
Kate
  • 1
0

When I create a date object:

new Date(year, month, day, hour, minute)

I works fine on localhost. When I deploy to server it breaks, because server is in another timezone.

I can't use getTimezoneOffset(). I need the timezoneOffset of my home - dependent on summertime/wintertime

// add diff minutes between myself (HOME) and server 
timezoneHomeOffset (d, tz = 'Europe/Copenhagen') {
  const utc = new Date(d.getTime())
  const dHome = new Date(d.toLocaleString('en-US', { timeZone: tz }))
  const diff = Math.round((utc - dHome) / 60000) // 60*1000 => minutes
  d.setMinutes(d.getMinutes() + diff)
  return d
}
Dale K
  • 16,372
  • 12
  • 37
  • 62
NBjerre
  • 91
  • 1
  • 2
0
const date = new Date("2020-12-16 17:45:00 UTC");

Works fine.

Dale K
  • 16,372
  • 12
  • 37
  • 62
0

It's actually not very hard at all to do this, but it certainly isn't intuitive to come up with the solution. There are some really convoluted answers here (though also some nice ones). Here's what I came up with to make sure my server timestamps would match my local timestamps, no matter what timezone my deployed server happened to be in.

(CET = Central European Timezone, which just happens to be my personal timezone; you can get the offset of any given timezone and calculate it and even make it an argument if you like, but for my purpose, I just needed to get my dates to all be the single desired consistent timezone.)

    const convertDateToCET = function(date) {
        date = new Date(date)
        // let startTime = date.getTime();
        const cetOffset = -120; // this is the number you get from running 
        // `(new Date()).getTimezoneOffset()` if you're on a machine in CET
        const offsetFromCET = (date.getTimezoneOffset() - cetOffset);
        const cetMillsecondOffset = ( cetOffset* 60 * 1000);
        date = new Date( date.getTime() - cetMillsecondOffset ) 
        // let endTime = date.getTime()
        // console.log("updated date from",startTime,"to",endTime)
        return date;
    },

Using this, you just make a time the way you would expect, e.g.

    let myDate = new Date("12-4-2021")
    myDate.setHour(14)
    myDate.setMinute(30)
    // now myDate is 2:30pm, December 4th, 2021, in whatever the timezone the machine of code running happens to be in
    myDate = convertDateToCET(myDate)
    // now myDate will show up as 2:30pm, Dec 4th, 2021, mapped into your local timezone
    // so, if you're in the UK, and one hour behind CET, myDate is now 1:30pm, Dec 4th, 2021

The key here is date.getTimezoneOffset(). If you're actually in CET, that number will be -120, and so it cancels out, making no difference (so CET results in CET out). If you're in the UK, one hour behind CET, that output would be -60, which means -60 + 120 = +60 which results in us changing the input time by one hour, and so on.

It probably makes more sense to convert everything and use everything in UTC for a case like this, but given that all of my input time is in CET and I'd originally developed the system based on how things looked locally on my machine, this utility allowed me to convert the existing code by just making a call to this function in a few key places.

Caution: Make sure not to apply this function call multiple times on the same date, as you'll be reapplying the offset multiple times, throwing it off!

Kyle Baker
  • 2,572
  • 1
  • 20
  • 25
-1

I used the timezone-js package.

var timezoneJS  = require('timezone-js');
var tzdata = require('tzdata');

createDate(dateObj) {
    if ( dateObj == null ) {
        return null;
    }
    var nativeTimezoneOffset = new Date().getTimezoneOffset();
    var offset = this.getTimeZoneOffset();

    // use the native Date object if the timezone matches
    if ( offset == -1 * nativeTimezoneOffset ) {
        return dateObj;
    }

    this.loadTimeZones();

    // FIXME: it would be better if timezoneJS.Date was an instanceof of Date
    //        tried jquery $.extend
    //        added hack to Fiterpickr to look for Dater.getTime instead of "d instanceof Date"
    return new timezoneJS.Date(dateObj,this.getTimeZoneName());
},
Thomas Bormans
  • 4,558
  • 5
  • 30
  • 46
-1

This worked for me. Not sure if it is a good idea though.

var myDate = new Date();
console.log('myDate:', myDate);   // myDate: "2018-04-04T01:09:38.112Z"

var offset = '+5';  // e.g. if the timeZone is -5

var MyDateWithOffset = new Date( myDate.toGMTString() + offset );   

console.log('MyDateWithOffset:', MyDateWithOffset); // myDateWithOffset: "2018-04-03T20:09:38.000Z"
Stephen Rauch
  • 40,722
  • 30
  • 82
  • 105
-12

This is BEST solution

Using:

// TO ALL dates
Date.timezoneOffset(-240) // +4 UTC

// Override offset only for THIS date
new Date().timezoneOffset(-180) // +3 UTC

Code:

Date.prototype.timezoneOffset = new Date().getTimezoneOffset();

Date.setTimezoneOffset = function(timezoneOffset) {
  return this.prototype.timezoneOffset = timezoneOffset;
};

Date.getTimezoneOffset = function() {
  return this.prototype.timezoneOffset;
};

Date.prototype.setTimezoneOffset = function(timezoneOffset) {
  return this.timezoneOffset = timezoneOffset;
};

Date.prototype.getTimezoneOffset = function() {
  return this.timezoneOffset;
};

Date.prototype.toString = function() {
  var offsetDate, offsetTime;
  offsetTime = this.timezoneOffset * 60 * 1000;
  offsetDate = new Date(this.getTime() - offsetTime);
  return offsetDate.toUTCString();
};

['Milliseconds', 'Seconds', 'Minutes', 'Hours', 'Date', 'Month', 'FullYear', 'Year', 'Day'].forEach((function(_this) {
  return function(key) {
    Date.prototype["get" + key] = function() {
      var offsetDate, offsetTime;
      offsetTime = this.timezoneOffset * 60 * 1000;
      offsetDate = new Date(this.getTime() - offsetTime);
      return offsetDate["getUTC" + key]();
    };
    return Date.prototype["set" + key] = function(value) {
      var offsetDate, offsetTime, time;
      offsetTime = this.timezoneOffset * 60 * 1000;
      offsetDate = new Date(this.getTime() - offsetTime);
      offsetDate["setUTC" + key](value);
      time = offsetDate.getTime() + offsetTime;
      this.setTime(time);
      return time;
    };
  };
})(this));

Coffee version:

Date.prototype.timezoneOffset = new Date().getTimezoneOffset()


Date.setTimezoneOffset = (timezoneOffset)->
    return @prototype.timezoneOffset = timezoneOffset


Date.getTimezoneOffset = ->
    return @prototype.timezoneOffset


Date.prototype.setTimezoneOffset = (timezoneOffset)->
    return @timezoneOffset = timezoneOffset


Date.prototype.getTimezoneOffset = ->
    return @timezoneOffset


Date.prototype.toString = ->
    offsetTime = @timezoneOffset * 60 * 1000
    offsetDate = new Date(@getTime() - offsetTime)
    return offsetDate.toUTCString()


[
    'Milliseconds', 'Seconds', 'Minutes', 'Hours',
    'Date', 'Month', 'FullYear', 'Year', 'Day'
]
.forEach (key)=>
    Date.prototype["get#{key}"] = ->
        offsetTime = @timezoneOffset * 60 * 1000
        offsetDate = new Date(@getTime() - offsetTime)
        return offsetDate["getUTC#{key}"]()

    Date.prototype["set#{key}"] = (value)->
        offsetTime = @timezoneOffset * 60 * 1000
        offsetDate = new Date(@getTime() - offsetTime)
        offsetDate["setUTC#{key}"](value)
        time = offsetDate.getTime() + offsetTime
        @setTime(time)
        return time
Maxmaxmaximus
  • 1,834
  • 1
  • 16
  • 16
  • 2
    Wow, I don't like it either, but I guess people _really_ hate you overriding the prototype of builtins! – Josh from Qaribou Apr 13 '18 at 21:41
  • @JoshfromQaribou There is nothing wrong with changing the prototype =) this is a myth and a common misconception. These people just think in a formulaic way, and do not apply critical thinking. They were told that this is bad, they blindly believe in it =) The Matrix is ​​everywhere ahah. – Maxmaxmaximus Aug 31 '20 at 10:28
  • @JoshfromQaribou It's bad to change the prototype IF you are writing a library. If you change the prototype as a PART of your project, then there is nothing wrong with that. For example, if in the future browsers add a method with the same name, then you simply override it =), and it also means that the CURRENT packages that you are using, and your code, DO NOT use the newly added property. These are the basics of javascript, but not everyone understands them =), the fact is that I am a genius programmer and there is a huge gap between my experience and the experience of ordinary people =) – Maxmaxmaximus Aug 31 '20 at 10:29