6
votes

Comment convertir une chaîne de date et d'heure en longue (UNIX Epoch Time) dans Java 8 (Scala)

Je veux l'heure UNIX Epoch (Heure Posix, Heure Unix) d'une chaîne dans un modèle , la chaîne est au format normal (donc UTC). Veuillez utiliser Java 8, pas Joda ou l'ancien Java.

(Pour des millisecondes, veuillez consulter Comment convertir une chaîne de date et d'heure en millisecondes longues (UNIX Epoch Time) en Java 8 (Scala) )

Jusqu'à présent, j'ai ce qui suit, mais je déteste ça pour plusieurs raisons:

  1. C'est beaucoup trop verbeux pour ce qui est la chose la plus courante à faire avec les dates (convertir en UNIX Epoch Time). La méthode 7 appelle ce qui devrait être 1.
  2. Il doit spécifier UTC, mais certainement UTC n'est qu'une valeur par défaut, pourquoi dois-je être explicite ici?
  3. Il a une chaîne littérale "UTC"
  4. Il a un nombre magique ZoneOffset.ofHours(0)

Mon meilleur jusqu'ici:

def dateTimeStringToEpoch(s: String, pattern: String): Long = 
    LocalDateTime.parse(s, DateTimeFormatter.ofPattern(pattern))
      .atZone(ZoneId.ofOffset("UTC", ZoneOffset.ofHours(0)))
      .toInstant().getEpochSeconds

Aussi, question bonus, est-ce efficace? Y a-t-il une surcharge pour créer le DateTimeFormatter via DateTimeFormatter.ofPattern (pattern) ? Si oui, pourquoi?


9 commentaires

Au moins, il existe une constante UTC ZoneOffset.UTC


À quoi ressemble l'entrée?


«C'est beaucoup trop verbeux»: c'est pourquoi les sous-programmes (aka fonctions ou méthodes) ont été inventés très tôt dans l'histoire des ordinateurs.


Oui, la création de DateTimeFormatter à chaque fois entraîne probablement une surcharge. Si vous êtes inquiet et que le schéma est le même, faites-en une constante. Vous pouvez le faire en toute sécurité, c'est thread-safe. Une méthode appelle moins pour chaque appel…


J'aurais pensé que cette question était un doublon (par exemple de Convertir un format de date à l'époque ), mais même si je n'utiliserais jamais un nombre d'appels de méthode comme métrique pour la qualité du code, il y a des points très intéressants qui ressortent dans les réponses.


Dans la plupart des langages, vous pouvez le faire en 2 appels ou moins (un pour analyser une structure, un pour convertir une structure en unix). Dans la programmation Unix C, vous pouvez le faire en 2, et C devrait vraiment définir la norme stackoverflow.com/a/1002631/1586965


C'est bien que nous n'ayons pas à être d'accord, @samthebest


@ OleV.V. Le nombre d'appels de méthodes natives n'est pas LA métrique, mais c'est utile. Supposons plutôt qu'il s'agissait de 1000 appels de méthode, vous pourriez, par cette seule information, savoir que le code doit être inutilement complexe, non?


"Quelle est la chose la plus courante à faire avec les dates (convertir en UNIX Epoch Time)." Vraiment? J'ai écrit beaucoup de code avec des dates, et je n'ai jamais eu à convertir une date en heure d'époque UNIX. De loin, la chose la plus courante que j'ai faite avec les dates est de les mettre en forme pour les afficher.


3 Réponses :


2
votes

Pouvez-vous essayer celui-ci, basé sur ce que vous avez dit, il analyse l'heure UTC, donc j'ai ceci comme exemple.

Instant.parse("2019-01-24T12:48:14.530Z").getEpochSecond


0 commentaires

2
votes

Celui-ci est plus de deux fois plus court ( seulement 3 appels de méthode ):

scala> val pattern = "yyyy/MM/dd HH:mm:ss"
pattern: String = yyyy/MM/dd HH:mm:ss

scala>   time(() => randomDates.map(dateTimeStringToEpoch(_, pattern)))
Took: 1216

scala>   time(() => randomDates.map(dateTimeStringToEpochFixed))
Took: 732

Btw, je construirais le DateTimeFormatter en dehors de dateTimeStringToEpoch et passez-le comme paramètre de méthode:

def dateTimeStringToEpoch(s: String, formatter: DateTimeFormatter): Long = 
     LocalDateTime.parse(s, formatter).toEpochSecond(ZoneOffset.UTC)

Après avoir exécuté un test de performance, il y a peu de différence de performance (à peine un facteur sur 2) en initialisant le DateTimeFormatter en dehors de la méthode.

def dateTimeStringToEpoch(s: String, pattern: String): Long = 
     LocalDateTime.parse(s, DateTimeFormatter.ofPattern(pattern))
                  .toEpochSecond(ZoneOffset.UTC)


1 commentaires

Il n'y a pas de méthode .toEpochMilli ici :(



3
votes

Vous pouvez utiliser l'équivalent du code Java suivant:

static long dateTimeStringToEpoch(String s, String pattern) {
    return DateTimeFormatter.ofPattern(pattern).withZone(ZoneOffset.UTC)
        .parse(s, p -> p.getLong(ChronoField.INSTANT_SECONDS));
}

Bien sûr, le traitement de DateTimeFormatter.ofPattern (pattern) .withZone (ZoneOffset.UTC) implique travail qui pourrait être évité en rencontrant la même chaîne de modèle plusieurs fois. La pertinence de cette quantité de travail pour votre application dépend de ce qui est fait à côté de cette opération.


2 commentaires

Très agréable! 4 appels de méthode au lieu de 7 (et je ne suis pas d'accord avec le demandeur selon lequel il devrait être 1; il y a un certain nombre de choses que nous voulons spécifier explicitement dans la conversion).


@ OleV.V. … Et le résultat de DateTimeFormatter.ofPattern (pattern) .withZone (ZoneOffset.UTC‌) pourrait être réutilisé, de sorte que l'opération réelle est le seul appel parse , renvoyant le valeur plutôt que quelque chose qui doit être converti.