Display date/time in user's locale format and time offset
Asked Answered
W

18

220

I want the server to always serve dates in UTC in the HTML, and have JavaScript on the client site convert it to the user's local timezone.

Bonus if I can output in the user's locale date format.

Wolfsbane answered 17/9, 2008 at 16:37 Comment(0)
W
220

Seems the most foolproof way to start with a UTC date is to create a new Date object and use the setUTC… methods to set it to the date/time you want.

Then the various toLocale…String methods will provide localized output.

Example:

// This would come from the server.
// Also, this whole block could probably be made into an mktime function.
// All very bare here for quick grasping.
d = new Date();
d.setUTCFullYear(2004);
d.setUTCMonth(1);
d.setUTCDate(29);
d.setUTCHours(2);
d.setUTCMinutes(45);
d.setUTCSeconds(26);

console.log(d);                        // -> Sat Feb 28 2004 23:45:26 GMT-0300 (BRT)
console.log(d.toLocaleString());       // -> Sat Feb 28 23:45:26 2004
console.log(d.toLocaleDateString());   // -> 02/28/2004
console.log(d.toLocaleTimeString());   // -> 23:45:26

Some references:

Wolfsbane answered 17/9, 2008 at 19:12 Comment(8)
In Firefox, toLocateDateString() returns something that looks like 'Sunday, January 12, 2014'..Grownup
Hmm yes, it is quite a serious problem. Using these methods will not work if you want the date to look the same across browsers. Any alternatives known?Linguistics
Single-line version of the above initialization: var d = new Date(Date.UTC(2004,1,29,2,45,26));Blunge
It may be worth considering that Chrome (as of v35) doesn't take into account the user's locale in the toLocaleString() functions.Gereron
+1 for below beautiful comments. alert(d); // -> Sat Feb 28 2004 23:45:26 GMT-0300 (BRT) alert(d.toLocaleString()); // -> Sat Feb 28 23:45:26 2004 alert(d.toLocaleDateString()); // -> 02/28/2004 alert(d.toLocaleTimeString()); // -> 23:45:26Wheedle
I'm sorry but this method doesn't work down under (I'm in Australia), when I run the above code the date is displayed in US format. Furthermore MDN says ' the locale used and the form of the string returned are entirely implementation dependent'.Lesley
@Lesley Did you ever manage to find a more reliable solution? I'm sitting with the same problem at the moment. Even though timezone displays as Australia, the locale remains en-US.Blamable
Creating a new date, then setting the parts individually can result in errors. E.g. creating a date for 31 Jan then setting the month to Feb will change the date to March. It should be done in one go: new Date(Date.UTC(year, month, ...)) which is also a lot less to type.Pongid
W
67

You can do it with moment.js (deprecated in 2021)

It's best to parse your date string from UTC as follows (create an ISO-8601 compatible string on the server to get consistent results across all browsers):

var m = moment("2013-02-08T09:30:26Z");

Now just use m in your application, moment.js defaults to the local timezone for display operations. There are many ways to format the date and time values or extract portions of it.

You can even format a moment object in the users locale like this:

m.format('LLL') // Returns "February 8 2013 8:30 AM" on en-us

To transform a moment.js object into a different timezone (i.e. neither the local one nor UTC), you'll need the moment.js timezone extension. That page has also some examples, it's pretty simple to use.

Note: Moment JS recommends more modern alternatives, so it is probably not a good choice for new projects.

Writhen answered 26/5, 2014 at 14:58 Comment(6)
How do you combine all this? m.utcOffset(offset).format('LLL') does not seem to work.Chromaticness
Should Luxon or Day.js be the suggested library now?Subassembly
I suggest adding For old projects, just use jQueryGaivn
Doesn't work on chrome - still shows am/pm even though time is set to 24h in computer's locale settingsBaneberry
momentjs has declared itself deprecated: momentjs.com/docs > Recently, Chrome Dev Tools started showing recommendations for replacing Moment for the size alone. We generally support this move.Scrimpy
Moment.js advices to use Day.js as replacementGreegree
E
25

You can use new Date().getTimezoneOffset()/60 for the timezone. There is also a toLocaleString() method for displaying a date using the user's locale.

Here's the whole list: Working with Dates

Ecuador answered 17/9, 2008 at 16:49 Comment(4)
toLocaleString is extremely unreliable for presenting dates in the format the a user might expect. Even where ISO 402 is supported, it is still very unreliable and bases the format on a language, not a locale.Pongid
@Pongid what is the solution instead of toLocaleString?Deviate
@user924—you can use a library, there are plenty to chose from. The problem with toLocaleString is that different implementations give different results with different levels of support for various languages and regions. E.g. my system default language is not en-US but the default format for toLocaleString for some browsers is the US format, others respect my system language. It's the same with timezone names, only worse as they aren't standardised at all. :-(Pongid
minor nitpick: you should negate the result to get the timezone in hours: -new Date().getTimezoneOffset()/60Nsf
N
17

In JS there are no simple and cross platform ways to format local date time, outside of converting each property as mentioned above.

Here is a quick hack I use to get the local YYYY-MM-DD. Note that this is a hack, as the final date will not have the correct timezone anymore (so you have to ignore timezone). If I need anything else more, I use moment.js.

var d = new Date();    
d = new Date(d.getTime() - d.getTimezoneOffset() * 60000)
var yyyymmdd = t.toISOString().slice(0, 10); 
// 2017-05-09T08:24:26.581Z (but this is not UTC)

The d.getTimezoneOffset() returns the time zone offset in minutes, and the d.getTime() is in ms, hence the x 60,000.

Nominate answered 9/5, 2017 at 6:52 Comment(1)
@VG I added some more info about where does the 60k comes from. Hope this help.Nominate
J
13

2021 - you can use the browser native Intl.DateTimeFormat

const utcDate = new Date(Date.UTC(2020, 11, 20, 3, 23, 16, 738));
console.log(new Intl.DateTimeFormat().format(utcDate));
// expected output: "21/04/2021", my locale is Switzerland

Below is straight from the documentation:

const date = new Date(Date.UTC(2020, 11, 20, 3, 23, 16, 738));
// Results below assume UTC timezone - your results may vary

// Specify default date formatting for language (locale)
console.log(new Intl.DateTimeFormat('en-US').format(date));
// expected output: "12/20/2020"
    
// Specify default date formatting for language with a fallback language (in this case Indonesian)
console.log(new Intl.DateTimeFormat(['ban', 'id']).format(date));
// expected output: "20/12/2020"
    
// Specify date and time format using "style" options (i.e. full, long, medium, short)
console.log(new Intl.DateTimeFormat('en-GB', { dateStyle: 'full', timeStyle: 'long' }).format(date));
// Expected output "Sunday, 20 December 2020 at 14:23:16 GMT+11"
Jesu answered 21/4, 2021 at 18:44 Comment(0)
C
8

Once you have your date object constructed, here's a snippet for the conversion:

The function takes a UTC formatted Date object and format string.
You will need a Date.strftime prototype.

function UTCToLocalTimeString(d, format) {
    if (timeOffsetInHours == null) {
        timeOffsetInHours = (new Date().getTimezoneOffset()/60) * (-1);
    }
    d.setHours(d.getHours() + timeOffsetInHours);

    return d.strftime(format);
}
Ceramic answered 13/5, 2010 at 21:35 Comment(3)
where did you strftime from ?Bearcat
Does setting the hours have any effect on the Day/Date/Year parts of a Date object? Doesn't seem to.Translocation
@ChristoKiwi—the value passed to setHours is expected to be an integer getTimezoneOffset()/60 may return a fraction (e.g. India offset of +05:30 will return 5.5). Decimals are truncated. Otherwise, setting the hours does update other values (set hours to 48 and see what happens).Pongid
C
8

// new Date(year, monthIndex [, day [, hours [, minutes [, seconds [, milliseconds]]]]])
var serverDate = new Date(2018, 5, 30, 19, 13, 15); // just any date that comes from server
var serverDateStr = serverDate.toLocaleString("en-US", {
  year: 'numeric',
  month: 'numeric',
  day: 'numeric',
  hour: 'numeric',
  minute: 'numeric',
  second: 'numeric'
})
var userDate = new Date(serverDateStr + " UTC");
var locale = window.navigator.userLanguage || window.navigator.language;

var clientDateStr = userDate.toLocaleString(locale, {
  year: 'numeric',
  month: 'numeric',
  day: 'numeric'
});

var clientDateTimeStr = userDate.toLocaleString(locale, {
  year: 'numeric',
  month: 'numeric',
  day: 'numeric',
  hour: 'numeric',
  minute: 'numeric',
  second: 'numeric'
});

console.log("Server UTC date: " + serverDateStr);
console.log("User's local date: " + clientDateStr);
console.log("User's local date&time: " + clientDateTimeStr);
Cung answered 21/2, 2019 at 18:29 Comment(1)
For the reference: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… (I needed the options part for my case)Gaivn
T
6

Here's what I've used in past projects:

var myDate = new Date();
var tzo = (myDate.getTimezoneOffset()/60)*(-1);
//get server date value here, the parseInvariant is from MS Ajax, you would need to do something similar on your own
myDate = new Date.parseInvariant('<%=DataCurrentDate%>', 'yyyyMMdd hh:mm:ss');
myDate.setHours(myDate.getHours() + tzo);
//here you would have to get a handle to your span / div to set.  again, I'm using MS Ajax's $get
var dateSpn = $get('dataDate');
dateSpn.innerHTML = myDate.localeFormat('F');
Thrown answered 17/9, 2008 at 16:59 Comment(2)
This is with ASP.NET-specific stuff.Grundy
Timezone offsets aren't necessarily even multiples of an hour, so getTimezoneOffset()/60 will often return a decimal value. This is particularly true for dates before 1900, where many places had offsets in minutes and seconds. Also, javascript Dates are now required to support historical offsets. E.g. in 1890 the offset in Moscow was +2:30:17. See Browsers, time zones, Chrome 67 Error.Pongid
I
4

With date from PHP code I used something like this..

function getLocalDate(php_date) {
  var dt = new Date(php_date);
  var minutes = dt.getTimezoneOffset();
  dt = new Date(dt.getTime() + minutes*60000);
  return dt;
}

We can call it like this

var localdateObj = getLocalDate('2015-09-25T02:57:46');
Incorporating answered 25/9, 2015 at 11:39 Comment(2)
The question was about JavaScript, not PHP.Flapper
Answer is in javascript only, It is mentioned in question that server date is in UTC. so server could be in any language. so I answered for PHP onlyIncorporating
A
4

I mix the answers so far and add to it, because I had to read all of them and investigate additionally for a while to display a date time string from db in a user's local timezone format.

The datetime string comes from a python/django db in the format: 2016-12-05T15:12:24.215Z

Reliable detection of the browser language in JavaScript doesn't seem to work in all browsers (see JavaScript for detecting browser language preference), so I get the browser language from the server.

Python/Django: send request browser language as context parameter:

language = request.META.get('HTTP_ACCEPT_LANGUAGE')
return render(request, 'cssexy/index.html', { "language": language })

HTML: write it in a hidden input:

<input type="hidden" id="browserlanguage" value={{ language }}/>

JavaScript: get value of hidden input e.g. en-GB,en-US;q=0.8,en;q=0.6/ and then take the first language in the list only via replace and regular expression

const browserlanguage = document.getElementById("browserlanguage").value;
var defaultlang = browserlanguage.replace(/(\w{2}\-\w{2}),.*/, "$1");

JavaScript: convert to datetime and format it:

var options = { hour: "2-digit", minute: "2-digit" };
var dt = (new Date(str)).toLocaleDateString(defaultlang, options);

See: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Date/toLocaleDateString

The result is (browser language is en-gb): 05/12/2016, 14:58

Audition answered 6/12, 2016 at 16:50 Comment(0)
O
3

The .getTimezoneOffset() method reports the time-zone offset in minutes, counting "westwards" from the GMT/UTC timezone, resulting in an offset value that is negative to what one is commonly accustomed to. (Example, New York time would be reported to be +240 minutes or +4 hours)

To the get a normal time-zone offset in hours, you need to use:

var timeOffsetInHours = -(new Date()).getTimezoneOffset()/60

Important detail:
Note that daylight savings time is factored into the result - so what this method gives you is really the time offset - not the actual geographic time-zone offset.

Oralle answered 17/9, 2008 at 17:48 Comment(0)
C
2

You could use the following, which reports the timezone offset from GMT in minutes:

new Date().getTimezoneOffset();

Note : - this function return a negative number.

Chaw answered 17/9, 2008 at 16:47 Comment(0)
T
2

The best solution I've come across is to create [time display="llll" datetime="UTC TIME" /] Tags, and use javascript (jquery) to parse and display it relative to the user's time.

http://momentjs.com/ Moment.js

will display the time nicely.

Treble answered 17/9, 2013 at 14:40 Comment(0)
T
1

getTimeZoneOffset() and toLocaleString are good for basic date work, but if you need real timezone support, look at mde's TimeZone.js.

There's a few more options discussed in the answer to this question

Tropic answered 17/9, 2008 at 16:56 Comment(0)
O
0

To convert date to local date use toLocaleDateString() method.

var date = (new Date(str)).toLocaleDateString(defaultlang, options);

To convert time to local time use toLocaleTimeString() method.

var time = (new Date(str)).toLocaleTimeString(defaultlang, options);
Outlying answered 10/7, 2018 at 7:31 Comment(1)
If you wanted an object instead of a String, this wouldn't necessarily be helpful .Wellturned
S
0

A very old question but perhaps this helps someone stumbling into this. Below code formats an ISO8601 date string in a human-friendly format corresponding the user's time-zone and locale. Adapt as needed. For example: for your app, are the hours, minutes, seconds even significant to display to the user for dates more than 1 days, 1 week, 1 month, 1 year or whatever old?

Also depending on your application's implementation, don't forget to re-render periodically. (In my code below at least every 24hours).

export const humanFriendlyDateStr = (iso8601) => {

  // Examples (using Node.js):

  // Get an ISO8601 date string using Date()
  // > new Date()
  // 2022-04-08T22:05:18.595Z

  // If it was earlier today, just show the time:
  // > humanFriendlyDateStr('2022-04-08T22:05:18.595Z')
  // '3:05 PM'

  // If it was during the past week, add the day:
  // > humanFriendlyDateStr('2022-04-07T22:05:18.595Z')
  // 'Thu 3:05 PM'

  // If it was more than a week ago, add the date
  // > humanFriendlyDateStr('2022-03-07T22:05:18.595Z')
  // '3/7, 2:05 PM'

  // If it was more than a year ago add the year
  // > humanFriendlyDateStr('2021-03-07T22:05:18.595Z')
  // '3/7/2021, 2:05 PM'

  // If it's sometime in the future return the full date+time:
  // > humanFriendlyDateStr('2023-03-07T22:05:18.595Z')
  // '3/7/2023, 2:05 PM'

  const datetime = new Date(Date.parse(iso8601))
  const now = new Date()
  const ageInDays = (now - datetime) / 86400000
  let str

  // more than 1 year old?
  if (ageInDays > 365) {
    str = datetime.toLocaleDateString([], {
      year: 'numeric',
      month: 'numeric',
      day: 'numeric',
      hour: 'numeric',
      minute: 'numeric',
    })
    // more than 1 week old?
  } else if (ageInDays > 7) {
    str = datetime.toLocaleDateString([], {
      month: 'numeric',
      day: 'numeric',
      hour: 'numeric',
      minute: 'numeric',
    })
    // more than 1 day old?
  } else if (ageInDays > 1) {
    str = datetime.toLocaleDateString([], {
      weekday: 'short',
      hour: 'numeric',
      minute: 'numeric',
    })
    // some time today?
  } else if (ageInDays > 0) {
    str = datetime.toLocaleTimeString([], {
      timeStyle: 'short',
    })
    // in the future?
  } else {
    str = datetime.toLocaleDateString([], {
      year: 'numeric',
      month: 'numeric',
      day: 'numeric',
      hour: 'numeric',
      minute: 'numeric',
    })
  }
  return str
}

Inspired from: https://alexwlchan.net/2020/05/human-friendly-dates-in-javascript/

Tested using Node.js

Schematism answered 8/4, 2022 at 22:27 Comment(0)
B
0

I'm using laravel to recieve sensor data from a backend database and process this information for dipslay and charting using javascript. Here's the approach I used to convert created_at time to my local time zone.

...
success: function(response){
      $('#dht_data_table').html(""); //clear table data under silent table refresh
      $.each(response.dht_data, function(key, dhtdata){ // cycle through table fetching sensor data
        // convert data recorded time in local  format
        var dht_datatimestamp = new Date(dhtdata.created_at).toLocaleString("en-US", {
                              localeMatcher: "best fit",
                              timeZoneName: "short"
                            });
...
`dht_data` is the sensor data object from the database passed via jquery response in json format.

Sample output result appears as:

7/3/2023, 12:38:27 PM GMT+3

Regards to this guide

Belloir answered 4/7, 2023 at 21:7 Comment(0)
D
-16

Don't know how to do locale, but javascript is a client side technology.

usersLocalTime = new Date();

will have the client's time and date in it (as reported by their browser, and by extension the computer they are sitting at). It should be trivial to include the server's time in the response and do some simple math to guess-timate offset.

Drucilla answered 17/9, 2008 at 16:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.