web-dev-qa-db-fra.com

Comment ignorer le fuseau horaire de l'utilisateur et forcer la date () à utiliser un fuseau horaire spécifique

Dans une application JS, je reçois un timestamp (eq. 1270544790922) du serveur (Ajax).

En me basant sur cet horodatage, je crée un objet Date en utilisant:

var _date = new Date();
_date.setTime(1270544790922);

Désormais, _date a décodé l'horodatage dans le fuseau horaire des paramètres régionaux de l'utilisateur actuel. Je ne veux pas ça.

J'aimerais que _date convertisse cet horodatage en heure actuelle dans la ville de Helsinki en Europe (sans tenir compte du fuseau horaire actuel de l'utilisateur). 

Comment puis je faire ça?

88
warpech

La valeur sous-jacente d'un objet Date est en réalité au format UTC. Pour le prouver, notez que si vous tapez new Date(0), vous verrez quelque chose comme: Wed Dec 31 1969 16:00:00 GMT-0800 (PST). 0 est traité comme 0 dans GMT, mais la méthode .toString() indique l'heure locale.

Grosse note, UTC signifie Universel code temporel. L’heure actuelle à deux endroits différents correspond au même UTC, mais la sortie peut être formatée différemment.

Nous avons besoin ici d'un peu de formatage

var _date = new Date(1270544790922); 
// outputs > "Tue Apr 06 2010 02:06:30 GMT-0700 (PDT)", for me
_date.toLocaleString('fi-FI', { timeZone: 'Europe/Helsinki' });
// outputs > "6.4.2010 klo 12.06.30"
_date.toLocaleString('en-US', { timeZone: 'Europe/Helsinki' });
// outputs > "4/6/2010, 12:06:30 PM"

Cela fonctionne mais .... vous ne pouvez utiliser aucune des autres méthodes de date pour vos besoins, car elles décrivent le fuseau horaire de l'utilisateur. Ce que vous voulez, c'est un objet de date associé au fuseau horaire d'Helsinki. À ce stade, vous avez le choix entre une bibliothèque tierce (je le recommande) ou hack-up l’objet de date afin que vous puissiez utiliser la plupart de ses méthodes.

Option 1 - un tiers comme moment-fuseau horaire

moment(1270544790922).tz('Europe/Helsinki').format('YYYY-MM-DD HH:mm:ss')
// outputs > 2010-04-06 12:06:30
moment(1270544790922).tz('Europe/Helsinki').hour()
// outputs > 12

Cela semble beaucoup plus élégant que ce que nous sommes sur le point de faire.

Option 2 - Pirater l'objet de date

var currentHelsinkiHoursOffset = 2; // sometimes it is 3
var date = new Date(1270544790922);
var helsenkiOffset = currentHelsinkiHoursOffset*60*60000;
var userOffset = _date.getTimezoneOffset()*60000; // [min*60000 = ms]
var helsenkiTime = new Date(date.getTime()+ helsenkiOffset + userOffset);
// Outputs > Tue Apr 06 2010 12:06:30 GMT-0700 (PDT)

Il pense toujours que c'est GMT-0700 (PDT), mais si vous ne fixez pas trop votre regard, vous pourrez peut-être confondre cela avec un objet de date utile pour vos besoins.

J'ai commodément sauté une partie. Vous devez pouvoir définir currentHelsinkiOffset. Si vous pouvez utiliser date.getTimezoneOffset() sur le côté serveur, ou simplement utiliser certaines instructions if pour décrire le moment où le fuseau horaire changera, cela devrait résoudre votre problème.

Conclusion - Je pense que pour cela, vous devriez utiliser une bibliothèque de dates comme moment-timezone .

59
Parris

Pour prendre en compte les millisecondes et le fuseau horaire de l'utilisateur, utilisez les éléments suivants:

var _userOffset = _date.getTimezoneOffset()*60*1000; // user's offset time
var _centralOffset = 6*60*60*1000; // 6 for central time - use whatever you need
_date = new Date(_date.getTime() - _userOffset + _centralOffset); // redefine variable
17
Ehren

Juste une autre approche

function parseTimestamp(timestampStr) {
  return new Date(new Date(timestampStr).getTime() + (new Date().getTimezoneOffset() * 60 * 1000));
};

//Sun Jan 01 2017 12:00:00
var timestamp = 1483272000000;
date = parseTimestamp(timestamp);
document.write(date);

À votre santé!

14
dheeran

Je soupçonne que le Answer ne donne pas le résultat correct. Dans la question, le demandeur souhaite convertir l’horodatage du serveur en heure actuelle à Hellsinki, en ignorant le fuseau horaire actuel de l’utilisateur.

C'est le fait que le fuseau horaire de l'utilisateur peut être ce que l'on veut, donc on ne peut pas lui faire confiance.

Si par exemple. l'horodatage est 1270544790922 et nous avons une fonction:

var _date = new Date();
_date.setTime(1270544790922);
var _helsenkiOffset = 2*60*60;//maybe 3
var _userOffset = _date.getTimezoneOffset()*60*60; 
var _helsenkiTime = new Date(_date.getTime()+_helsenkiOffset+_userOffset);

Lorsqu'un New-Yorkais visite la page, l'alerte (_helsenkiTime) imprime:

Tue Apr 06 2010 05:21:02 GMT-0400 (EDT)

Et quand un Finlandais visite la page, alert (_helsenkiTime) imprime:

Tue Apr 06 2010 11:55:50 GMT+0300 (EEST)

La fonction est donc correcte uniquement si le visiteur de la page a le fuseau horaire cible (Europe/Helsinki) sur son ordinateur, mais échoue dans presque toutes les autres parties du monde. Et comme l’horodatage du serveur est généralement un horodatage UNIX, qui est par définition en UTC, le nombre de secondes écoulées depuis l’époque Unix (1 er janvier 1970 00:00:00 GMT), nous ne pouvons pas déterminer DST ni non DST à partir d’horodatage.

La solution consiste donc à DÉCOMPTIVER le fuseau horaire actuel de l'utilisateur et à mettre en œuvre un moyen de calculer le décalage UTC, que la date soit en heure avancée ou non. Javascript n'a pas de méthode native pour déterminer l'historique de transition DST d'un fuseau horaire autre que le fuseau horaire actuel de l'utilisateur. Nous pouvons y parvenir plus simplement en utilisant un script côté serveur, car nous avons un accès facile à la base de données de fuseaux horaires du serveur avec l'historique de transition complet de tous les fuseaux horaires.

Mais si vous n'avez pas accès à la base de données de fuseau horaire du serveur (ou de tout autre serveur) ET si l'horodatage est au format UTC, vous pouvez obtenir la même fonctionnalité en codant en dur les règles DST en Javascript.

Pour couvrir les dates des années 1998 - 2099 en Europe/Helsinki, vous pouvez utiliser la fonction suivante ( jsfiddled ): 

function timestampToHellsinki(server_timestamp) {
    function pad(num) {
        num = num.toString();
        if (num.length == 1) return "0" + num;
        return num;
    }

    var _date = new Date();
    _date.setTime(server_timestamp);

    var _year = _date.getUTCFullYear();

    // Return false, if DST rules have been different than nowadays:
    if (_year<=1998 && _year>2099) return false;

    // Calculate DST start day, it is the last sunday of March
    var start_day = (31 - ((((5 * _year) / 4) + 4) % 7));
    var SUMMER_start = new Date(Date.UTC(_year, 2, start_day, 1, 0, 0));

    // Calculate DST end day, it is the last sunday of October
    var end_day = (31 - ((((5 * _year) / 4) + 1) % 7))
    var SUMMER_end = new Date(Date.UTC(_year, 9, end_day, 1, 0, 0));

    // Check if the time is between SUMMER_start and SUMMER_end
    // If the time is in summer, the offset is 2 hours
    // else offset is 3 hours
    var hellsinkiOffset = 2 * 60 * 60 * 1000;
    if (_date > SUMMER_start && _date < SUMMER_end) hellsinkiOffset = 
    3 * 60 * 60 * 1000;

    // Add server timestamp to midnight January 1, 1970
    // Add Hellsinki offset to that
    _date.setTime(server_timestamp + hellsinkiOffset);
    var hellsinkiTime = pad(_date.getUTCDate()) + "." + 
    pad(_date.getUTCMonth()) + "." + _date.getUTCFullYear() + 
    " " + pad(_date.getUTCHours()) + ":" +
    pad(_date.getUTCMinutes()) + ":" + pad(_date.getUTCSeconds());

    return hellsinkiTime;
}

Exemples d'utilisation:

var server_timestamp = 1270544790922;
document.getElementById("time").innerHTML = "The timestamp " + 
server_timestamp + " is in Hellsinki " + 
timestampToHellsinki(server_timestamp);

server_timestamp = 1349841923 * 1000;
document.getElementById("time").innerHTML += "<br><br>The timestamp " + 
server_timestamp + " is in Hellsinki " + timestampToHellsinki(server_timestamp);

var now = new Date();
server_timestamp = now.getTime();
document.getElementById("time").innerHTML += "<br><br>The timestamp is now " +
server_timestamp + " and the current local time in Hellsinki is " +
timestampToHellsinki(server_timestamp);​

Et cela affiche les éléments suivants, quel que soit le fuseau horaire de l'utilisateur:

The timestamp 1270544790922 is in Hellsinki 06.03.2010 12:06:30

The timestamp 1349841923000 is in Hellsinki 10.09.2012 07:05:23

The timestamp is now 1349853751034 and the current local time in Hellsinki is 10.09.2012 10:22:31

Bien sûr, si vous pouvez renvoyer l’horodatage sous une forme dont le décalage (DST ou non DST) est déjà ajouté à l’horodatage sur le serveur, vous n’aurez pas à le calculer côté client et vous pourrez beaucoup simplifier la fonction. MAIS rappelez-vous de NE PAS utiliser timezoneOffset (), car vous devez alors gérer le fuseau horaire de l'utilisateur et il ne s'agit pas du comportement souhaité.

13
Timo Kähkönen

En supposant que vous obteniez l'horodatage à l'heure d'Helsinki, je créerais un objet de date défini à minuit le 1er janvier 1970 UTC (pour ne pas tenir compte des paramètres de fuseau horaire local du navigateur) . Ajoutez-y simplement le nombre de millisecondes requis.

var _date	= new Date( Date.UTC(1970, 0, 1, 0, 0, 0, 0) );
_date.setUTCMilliseconds(1270544790922);

alert(_date); //date shown shifted corresponding to local time settings
alert(_date.getUTCFullYear());    //the UTC year value
alert(_date.getUTCMonth());       //the UTC month value
alert(_date.getUTCDate());        //the UTC day of month value
alert(_date.getUTCHours());       //the UTC hour value
alert(_date.getUTCMinutes());     //the UTC minutes value

Surveillez plus tard, pour toujours demander les valeurs UTC à partir de l'objet date. De cette façon, les utilisateurs verront les mêmes valeurs de date indépendamment des paramètres locaux. Sinon, les valeurs de date seront décalées en fonction des réglages de l'heure locale.

2
Tibor

Vous pouvez utiliser setUTCMilliseconds()

var _date = new Date();
_date.setUTCMilliseconds(1270544790922);
0
jimasun