Elie
Elie

Reputation: 7363

Javascript DateFormat for different timezones

I'm a Java developer and I'm used to the SimpleDateFormat class that allows me to format any date to any format by settings a timezone.

Date date = new Date();

SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy hh:mm:ss");

sdf.setTimeZone(TimeZone.getTimeZone("America/Los_Angeles"));
System.out.println(sdf.format(date)); // Prints date in Los Angeles

sdf.setTimeZone(TimeZone.getTimeZone("America/Chicago"));
System.out.println(sdf.format(date)); // Prints same date in Chicago

SimpleDateFormat is a pretty neat solution in Java but unfortunately I can't find any similar alternative in Javascript.

I'm extending the Date prototype in Javascript to do exactly the same. I have dates in Unix format but I want to format them in different timezones.

Date.prototype.format = function(format, timezone) {
    // Now what?
    return formattedDate;
}

I'm looking for a neat way to do this rather than a hack.

Thanks

Upvotes: 18

Views: 83922

Answers (9)

Steven Hoyt
Steven Hoyt

Reputation: 1

This is a JavaScript port of PHP's date function:

e.g.

console.log( new Date("2023-01-01").return("M d Y") )

returns "JAN 01 2023"

console.log ( new Date("1980-01-01").return("\\\\D\\\\av\\\\i\\\\d \\\\w\\\\a\\\\s bor\\\\n o\\\\n M d Y \\\\a\\\\n\\\\d \\\\here'\\\\s t\\\\he e\\\\s\\\\c\\\\ape \\\\c\\\\h\\\\ar \\\\\\")

returns "David was born on JAN 01 1980 and here's the escape char \\"

if (!Date.prototype.return) {
    Date.prototype.return = function (format) {
        if (isNaN(this.valueOf()) || !this.valueOf()) { return null; }
        let days        = ["SUN", "MON", "TUE", "WED", "THR", "FRI", "SAT"];
        let months      = ["JANUARY", "FEBRUARY", "MARCH", "APRIL", "MAY", "JUNE", "JULY", "AUGUST", "SEPTEMBER", "OCTOBER", "NOVEMBER", "DECEMBER"];
        let newDate     = new Date(this.getTime() + this.getTimezoneOffset() * 60000);
        let month       = newDate.getMonth();
        let weekDay     = newDate.getDay();
        let day         = newDate.getDate();
        let year        = newDate.getFullYear();
        let hour        = newDate.getHours();
        let minute      = newDate.getMinutes();
        let second      = newDate.getSeconds();
        let string      = [];
        let escapeNext  = false;
        for (const character of format) {
            if (escapeNext) {
                string.push(character);
                escapeNext = false;
            } else if (character === "\\") {
                escapeNext = true;
            } else {
                switch (character) {
                    case "a": string.push(hour < 12 ? "AM" : "PM");             break;
                    case "c": string.push(newDate.toISOString());               break;
                    case "d": string.push(String("0" + day).slice(-2));         break;
                    case "D": string.push(days[weekDay]);                       break;
                    case "F": string.push(months[month]);                       break;
                    case "g": let h = hour === 0 ? 12 : hour;                   
                              string.push(h > 12 ? h - 12 : h);                 
                              break;                                            
                    case "h": h = hour === 0 ? 12 : hour;                       
                              h = h > 12 ? h - 12 : h;                          
                              string.push(String("0" + h).slice(-2));           
                              break;                                            
                    case "H": string.push(String("0" + hour).slice(-2));        break;
                    case "i": string.push(String("0" + minute).slice(-2));      break;
                    case "j": string.push(day);                                 break;
                    case "l": string.push(days[weekDay]);                       break;
                    case "m": string.push(String("0" + (month + 1)).slice(-2)); break;
                    case "M": string.push(months[month].substring(0, 3));       break;
                    case "n": string.push(month + 1);                           break;
                    case "s": string.push(String("0" + second).slice(-2));      break;
                    case "w": string.push(weekDay);                             break;
                    case "y": string.push(year.toString().slice(-2));           break;
                    case "Y": string.push(year);                                break;
                    default : string.push(character);
                }
            }
        }
        return string.join("");
    };
}

Upvotes: 0

j4ys0n
j4ys0n

Reputation: 730

There is a way to format for time zones.

console.log(new Date().toLocaleDateString('en-US', {timeZone: 'America/Denver'}))
// 11/13/2018
console.log(new Date().toLocaleTimeString('en-US', {timeZone: 'America/Denver'}))
// 2:30:54 PM
console.log(new Date().toLocaleTimeString('en-US', {timeZone: 'America/New_York'}))
// 4:31:26 PM

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

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toLocaleTimeString

Upvotes: 27

Dark Light
Dark Light

Reputation: 1250

Since my requirement was a typescript solution but I stumbled here I used this answer to write my typescript function.

Based on answer above, a function in typescript which converts a timestamp or a date object into a formatted local time string.

const formatDateString = (date_or_ts:Date|number):string=>{
    let obj:Date;

    if(typeof date_or_ts === "number"){
        obj = new Date(date_or_ts*1000);
        // obj=new Date(obj.getTime()+obj.getTimezoneOffset()*60000+timezone*3600000);
    }else{
        obj = date_or_ts;
    }
    const format = "dd-MM-yyyy hh:mm:ss";
    let two=function(s:number){
        return s<10?"0"+s:s+"";
    }
    return format.replace(/dd|MM|yyyy|hh|mm|ss/g, function(pattern){
        const months = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];
        switch(pattern){
            case "dd" : return two(obj.getDate()).toString();
            case "MM" : return months[obj.getMonth()];
            case "yyyy" : return obj.getFullYear().toString();
            case "hh" : return two(obj.getHours()).toString();
            case "mm" : return two(obj.getMinutes()).toString();
            case "ss" : return two(obj.getSeconds()).toString();
            default: return "";
        }
    });
}

Upvotes: 0

Henrik N
Henrik N

Reputation: 16284

This is an old question, but since I found it:

As mentioned, there's nothing reasonable built-in.

As for libs, there is Moment Timezone for Moment.js.

Here is a JSfiddle with an example: http://jsfiddle.net/kunycrkb/

The same code inline:

var m = moment("2014-06-01T13:05:00Z");
var f = "HH:mm z";

$("#results").text(m.tz("UTC").format(f) + " is " + m.tz("EST").format(f) +  "!");

Upvotes: 1

Garrett
Garrett

Reputation: 3023

The ISO Extended format for common date is YYYY-MM-DD, and for time is hh:mm:ss. Either format can be understood, unambiguously, worldwide.

See also: http://jibbering.com/faq/#dates

Upvotes: 3

aaaaaaaaaaaa
aaaaaaaaaaaa

Reputation: 3700

You are clearly asking two questions in one, formatting and time zone. They need to be addressed separately. Formatting is pretty trivial, if none of the other answers will do for that you will have to be more specific.

As for the time and time zone, if you have your server inject the UTC time, preferably as UNIX time in milliseconds, into the JavaScript, you can compare that to the time on the client machine, and thus work out how far from UTC the client is. Then you can calculate the time of any time zone you want.

Edit: I actually didn't know JavaScript also had built in UTC time until I checked on the internet, neat.

In any case, I suppose this is want you want:

Date.prototype.format=function(format,timezone){
    var obj=new Date(this.getTime()+this.getTimezoneOffset()*60000+timezone*3600000);
    var two=function(s){
        return s<10?"0"+s:s+"";
    }
    return format.replace(/dd|MM|yyyy|hh|mm|ss/g, function(pattern){
        switch(pattern){
            case "dd" : return two(obj.getDate());
            case "MM" : return two(obj.getMonth()+1);
            case "yyyy" : return obj.getFullYear();
            case "hh" : return two(obj.getHours());
            case "mm" : return two(obj.getMinutes());
            case "ss" : return two(obj.getSeconds());
        }
    });
}

You can add in more patterns if you need.

Upvotes: 1

M&#225;r &#214;rlygsson
M&#225;r &#214;rlygsson

Reputation: 14606

Attempting to (ever so slightly) improve upon mwilcox's suggestion:

Date.prototype.format = function(format, tzAdjust) {

    // get/setup a per-date-instance tzDate object store
    var tzCache = this.__tzCache = this.__tzCache || (this.__tzCache = {});

    // fetch pre-defined date from cache 
    var tzDate = tzCache[tzAdjust];
    if ( !tzDate )
    {
      // on miss - then create a new tzDate and cache it
      tzDate = tzCache[tzAdjust] = new Date( this );
      // adjust by tzAdjust (assuming it's in minutes 
      // to handle those weird half-hour TZs :) 
      tzDate.setUTCMinutes( tzDate.getUTCMinutes()+tzAdjust );
    }

    return format.replace(/dd|MM|yyyy|hh|mm|ss/g, function(pattern){
               // replace each format tokens with a value 
               // based on tzDate's corresponding UTC property
             });
}

Upvotes: 1

Pointy
Pointy

Reputation: 413757

Don't write your own stuff; just get datejs: http://www.datejs.com/

You can figure out what the timezone offset is set to in the execution environment like this:

var local = new Date();
var utc = Date.UTC(local.getFullYear(), local.getMonth(), local.getDate(), local.getHours(), local.getMinutes(), local.getSeconds(), local.getMilliseconds());
var tz = (utc - local.getTime()) / (60 * 60 * 1000);

Upvotes: 0

mwilcox
mwilcox

Reputation: 4132

If you're just passing the raw TZ there's nothing really complicated about adjusting the hours. My example below is of course abbreviated. Yours may get quite long depending on how many patterns you'd handle.

Date.prototype.format = function(format, tzAdjust) {
    // adjust timezone
    this.setHours(this.getHours()+tzAdjust)
    // pad zero helper - return "09" or "12"
    var two = function(s){ return s+"".length==1 ? "0"+s : s+""; }
    // replace patterns with date numbers
    return format.replace(/dd|MM|yyyy|hh|mm|ss/g, function(pattern){
        switch(pattern){
            case "d" : return this.getDate();
            case "dd" : return two(this.getDate());
        }
    });
}

Upvotes: 1

Related Questions