Mise à jour : Après avoir essayé d'utiliser ces fonctions dans un datetime
j'ai remarqué que le passage de mars à avril faisait basculer le fuseau horaire comme prévu, puisque ma zone bascule dans l'heure d'été en mars. De manière inattendue, le passage au fuseau horaire suivant a eu lieu au lieu de basculer entre l'heure normale et l'heure d'été dans le même fuseau horaire.
Il s'avère que c'est parce que mes fonctions originales créaient toujours new Date()
pour le moment présent ou pour un moment fixe arbitraire dans le passé. En comparant cela aux heures relatives de mars et d'avril, il aurait logiquement détecté le basculement de l'heure d'été comme un changement de fuseau horaire.
La solution était de passer les temps relatifs dans les fonctions d'utilité, ainsi toutes mes comparaisons étaient pour le temps relatif au lieu de maintenant ou le temps fixe arbitraire. J'ai perdu un peu de la compacité, mais maintenant la logique fonctionne comme il faut.
Mises à jour du flux de travail :
-
t
La valeur par défaut du paramètre new Date()
- Pour le temps fixe, passer dans un
Date
- Pour l'heure actuelle, passez dans
null
ou rien
-
std()
mis à jour pour utiliser t.setMonth(v);
pour changer le mois pour les heures fixes
-
.getTimezoneOffset()
ne peut pas être enchaîné à .setMonth()
Nous devons donc passer de la notation à une ligne à l'utilisation de fermetures ( {}
), les terminaisons ( ;
), et return
-
console.log()
L'exemple passe en boucle chaque mois ( 0
a 11
)
- L'objet à date fixe doit être cloné en utilisant le même horodatage (
let ts = +t;
)
- El
+
avant le Date
le transforme en un number
avec l'horodatage Unix
-
Date()
accepte également les timestamps Unix pour créer des temps fixes
- Si nous ne le clonons pas, chaque appel passera autour de la même
Date
avec les mois fixés à 6
ce qui va à l'encontre du but recherché
- Ok, nous ne clonons pas vraiment, nous créons simplement un nouvel objet en utilisant les mêmes paramètres ; même différence ;)
let ns = {
std: (t = new Date()) => Math.max(...[0, 6].map(v => {
t.setMonth(v);
return t.getTimezoneOffset();
})),
is_dst: (t = new Date()) => t.getTimezoneOffset() < ns.std(t),
utc: (t, std = 0) => {
t = t || new Date();
let z = std ? ns.std(t) : t.getTimezoneOffset(),
zm = z % 60;
return 'UTC' + (z > 0 ? '-' : '+') + (z / 60) + (zm ? ':' + zm : '');
}
};
//current time only
console.log(ns.std(), ns.is_dst(), ns.utc(), ns.utc(null, 1));
//iterate each month
let t = new Date(2021,0,1);
for (let i = 0; i < 12; i++) {
t.setMonth(i);
let ts = +t;
console.log(t.toDateString().split(" ")[1], ns.std(new Date(ts)), ns.is_dst(new Date(ts)), ns.utc(new Date(ts)), ns.utc(new Date(ts), 1));
}
Développer la solution compacte et cryptique de @nkitku pour la transformer en un ensemble de fonctions réutilisables.
Flux de travail :
- Toutes les fonctions ont une portée dans un espace de nom.
ns
afin qu'elles n'entrent pas en conflit avec d'autres fonctions du code qui peuvent avoir le même nom.
- L'espacement des noms permet également une notation compacte des fonctions ;
std: ()=>Math.max(),
est équivalent à function std(){ return Math.max(); }
-
std()
renvoie le décalage du fuseau horaire en heure normale
-
[0, 6]
met en place une comparaison d'un mois sans DST et d'un mois avec DST
-
0
pour le mois de janvier, puisque Date.setMonth()
est indexé à zéro
-
6
pour le mois de juillet
- Apparemment, l'heure normale n'est pas en janvier pour tout le monde, donc nous devons vérifier à la fois en janvier et en juillet.
-
...[]
convertit le Array
de mois à un Set
afin que nous puissions appliquer la map()
fonction
- Les tableaux bruts ne peuvent pas fonctionner
map()
-
map()
exécute un ensemble de variables sur la même fonction et renvoie un tableau de résultats
- Créer un nouveau
Date
objet avec année, mois, jour
- L'année (
95
dans l'exemple) est arbitraire puisque l'année n'est pas importante pour ce calcul.
- Le mois se branche sur nos valeurs
[0, 6]
en tant que variable v
- Le jour (
1
dans l'exemple) est également arbitraire
- Logiquement, nous aurions pu créer un
new Date()
alors .setMonth(v)
mais l'utilisation des nombres arbitraires est plus compacte et plus rapide.
- Maintenant que nous avons les dates,
getTimezoneOffset()
retourne les décalages pour chaque mois et les pousse dans le tableau de résultats
-
Math.max()
trouve la plus grande valeur parmi les résultats, qui sera le décalage de l'heure standard.
-
is_dst()
vérifie si c'est actuellement l'heure d'été.
-
new Date().getTimezoneOffset()
obtient le décalage actuel, avec ou sans DST
-
ns.std()
obtient le décalage en heure normale
- Si le décalage actuel est inférieur, il s'agit d'un DST.
-
utc()
renvoie une chaîne de caractères en notation UTC
- El
std
le paramètre est désactivé par défaut
-
z = std ? ns.std() : new Date().getTimezoneOffset()
règle l'heure sur DST ou standard en fonction du drapeau
-
zm = z % 60
captures minutes car certaines zones utilisent 30 minutes par exemple
-
(z > 0 ? '-' : '+')
attribue le signe correct selon la notation UTC ; les valeurs de décalage positives sont indiquées comme des décalages négatifs dans la notation.
-
(z / 60)
saisit les heures dans un format à un chiffre selon la notation, donc pas besoin de .toString().padStart(2,'0
)` pour le format à deux chiffres
-
(zm ? ':' + zm : '')
Ajoute les minutes si elles existent pour le fuseau horaire.
Cette version étant destinée à être compacte, vous pourriez gagner encore plus de place en supprimant les espaces blancs superflus. Mais c'est là le travail d'un mineur.
std:()=>Math.max(...[0,6].map(v=>new Date(95,v,1).getTimezoneOffset())),
const ns = {
std: () => Math.max(...[0, 6].map(v => new Date(95, v, 1).getTimezoneOffset())),
is_dst: () => new Date().getTimezoneOffset() < ns.std(),
utc: (std = 0) => {
let z = std ? ns.std() : new Date().getTimezoneOffset(),
zm = z % 60;
return 'UTC' + (z > 0 ? '-' : '+') + (z / 60) + (zm ? ':' + zm : '');
}
};
console.log(ns.std(), ns.is_dst(), ns.utc(), ns.utc(1));