Maison > Java > javaDidacticiel > le corps du texte

Faisons les dates correctement

王林
Libérer: 2024-08-05 20:17:30
original
1067 Les gens l'ont consulté

Lets do dates properly

En tant que débutant, l'un des sujets les plus intéressants que vous apprendrez sont les dates. Même si cela peut paraître un peu ennuyeux, c'est l'une des choses clés que vous savez peut-être ; à partir de votre base de données, de votre API, de votre interface graphique, etc., apprendre à gérer correctement les dates est un facteur clé pour écrire de bonnes applications.

Avant de commencer

Un détail important dont vous devez vous souvenir est que Java a été précipité pour le Web, vous disposez donc de nombreuses façons originales et quelque peu stupides de faire les choses. Le but de ce guide sera de vous apprendre à utiliser les dernières API Java pour écrire du bon code efficace. Mon objectif est de vous apprendre à ne pas coder quoi que ce soit de difficile et à utiliser plutôt l'ISO standardisé pour une application évolutive.

Comment travailler avec les dates

L'API des dates

À partir de Java 8 SE avec la sortie de la classe Date définie comme :

La classe Date représente un instant spécifique, avec une précision à la milliseconde.

Également plus loin, nous avons eu l'ajout de la classe Abstract Calender (avec une mise à niveau significative avec JDK 1.1) définie comme :

La classe Calendar est une classe abstraite qui fournit des méthodes pour convertir entre un instant spécifique et un ensemble de champs de calendrier tels que ANNÉE, MOIS, DAY_OF_MONTH, HOUR, etc., et pour manipuler les champs de calendrier, tels que obtenir la date de la semaine prochaine. Un instant dans le temps peut être représenté par une valeur en milliseconde qui est un décalage par rapport à Epoch, 1er janvier 1970 00:00:00.000 GMT (grégorien).

Comme l'ont noté les documents Oracle, la raison était le manque de capacités d'internationalisation.

Il est bon de noter que la même documentation liée ci-dessus donne plus de détails sur son timing si elle vous intéresse.

L'API LocalDate

Également avec Java 8 SE est apparue la classe LocalDate qui est référencée :

Une date sans fuseau horaire dans le système de calendrier ISO-8601, comme le 03/12/2007.
LocalDate est un objet date-heure immuable qui représente une date, souvent considérée comme année-mois-jour. D'autres champs de date, tels que le jour de l'année, le jour de la semaine et la semaine de l'année, sont également accessibles. Par exemple, la valeur « 2 octobre 2007 » peut être stockée dans un LocalDate.

Une spécification importante à prendre en compte est :

Cette classe ne stocke ni ne représente une heure ou un fuseau horaire. Il s'agit plutôt d'une description de la date, telle qu'elle est utilisée pour les anniversaires. Il ne peut pas représenter un instant sur la timeline sans informations supplémentaires telles qu'un décalage ou un fuseau horaire.

Différence et lequel utiliser

Problèmes avec les API Date/Heure

Une lecture plus approfondie de la classe LocalDate vous mènera à « Cette classe est immuable et thread-safe ». Cela nous amène à notre premier problème.

  • La date et le calendrier n'étaient pas thread-safe. Si vous êtes un peu confus quant à ce que cela signifie, les threads sont un moyen d'implémenter la concurrence avec une application informatique, ce qui permet à plusieurs tâches de s'exécuter simultanément plutôt que séquentiellement (si vous avez une expérience en programmation, vous pouvez voir cela comme asynchrone) .
  • Un autre problème avec l'API Date/Calender était sa mauvaise conception. Plus tard, il a été remanié pour être centré sur l'ISO (si vous êtes un peu perdu sur ce qu'est tout ce truc ISO ; en bref, ISO signifie « Organisation internationale de normalisation »). Et nous en verrons les avantages supplémentaires plus tard.
  • Et enfin, pour revenir au manque d'internationalisation, les développeurs étaient tenus d'écrire leur logique pour gérer les différents fuseaux horaires, ce qui peut entraîner de nombreuses erreurs telles que des correspondances manquées.

La vraie différence

La plus grande différence est que, malgré le nom, Date stockerait à la fois l'heure et la date (comme mentionné par la documentation avec un décalage en millisecondes depuis l'époque - nous parlerons de l'époque plus tard). Avec la nouvelle API, nous avons accès à un formatage/analyse/manipulation plus facile des dates.

Et si je souhaite également stocker du temps ?

Eh bien, Java vous couvre également avec sa classe LocalDateTime

Une date-heure sans fuseau horaire dans le système de calendrier ISO-8601, tel que 2007-12-03T10:15:30.
LocalDateTime est un objet date-heure immuable qui représente une date-heure, souvent considérée comme année-mois-jour-heure-minute-seconde. D'autres champs de date et d'heure, tels que le jour de l'année, le jour de la semaine et la semaine de l'année, sont également accessibles. Le temps est représenté avec une précision de la nanoseconde. Par exemple, la valeur "2 octobre 2007 à 13:45.30.123456789" peut être stockée dans un LocalDateTime.

Si vous voulez uniquement stocker l'heure alors vous pouvez utiliser la classe LocalTime

Petit récapitulatif rapide et cas d'utilisation

Name Should Use Use Case Example
LocalDate Interprating Dates 2021-02-28
LocalTime Interprating Time 19:32:25.457826
LocalDateTime Interprating Time/Date 2021-02-28T19:32:25.457826.
Date prefer not Represents Time Tue Jul 12 18:35:37 IST 2016

Date Locale

Maintenant que nous avons une bonne compréhension de son arrière-plan et de ce que nous pouvons en faire, explorons les méthodes de la classe LocalDate.

OIN 8601

Le système de calendrier ISO-8601 est le système de calendrier civil moderne utilisé aujourd'hui dans la plupart des pays du monde. Il équivaut au système de calendrier grégorien proleptique, dans lequel les règles actuelles relatives aux années bissextiles sont appliquées à tout moment. Pour la plupart des applications écrites aujourd'hui, les règles ISO-8601 sont tout à fait adaptées. Cependant, toute application utilisant des dates historiques et exigeant qu'elles soient exactes trouvera l'approche ISO-8601 inappropriée.

C'est le standard que Java utilisera pour formater correctement nos dates.

Temporel

Avant d'approfondir, je souhaite vous présenter l'objet Temporal que toutes les nouvelles API Date implémentent (LocalDate, LocalTime, LocalDateTime), il est défini comme :

Il s'agit du type d'interface de base pour les objets de date, d'heure et de décalage qui sont suffisamment complets pour être manipulés à l'aide de plus et de moins. Il est implémenté par les classes qui peuvent fournir et manipuler des informations sous forme de champs ou de requêtes. Voir TemporalAccessor pour la version en lecture seule de cette interface.

Je ne vais pas approfondir ce sujet, je voulais juste que vous compreniez ce que c'est si vous le rencontrez.

Méthodes

Le format sera dans l'ordre - Le nom de la méthode, la description du retour spécifiée et un résumé rapide de ce qu'elle fait/ou une plongée en profondeur. Si vous voulez suivre, je vais utiliser jshell, importez simplement java.time.LocalDate et copiez les mêmes méthodes.

LocalDate.now() : > la date actuelle en utilisant l'horloge système et le fuseau horaire par défaut, non nul

Comme mentionné dans la description, il renverra le format de date actuel en fonction du fuseau horaire, par exemple, pour moi, il donne le 10/07/2024, mais le format peut changer en fonction de l'heure locale en fonction du format ISO 8601 attribué à votre pays. (par exemple, cela pourrait être le 2024.07.10 ou le 24/7/10, c'est une norme que votre pays utiliserait)

La méthode LocalDate.now() peut prendre un argument. Pour l'utiliser, nous importerons java.time.ZoneId.

Qu’est-ce que ZoneId ?

ZoneId publié avec Java 8SE défini comme :

Un ZoneId est utilisé pour identifier les règles utilisées pour convertir entre un Instant et un LocalDateTime. Il existe deux types distincts de pièces d'identité :

  • Décalages fixes - un décalage entièrement résolu par rapport à UTC/Greenwich, qui utilise le même décalage pour toutes les dates-heures locales
  • Régions géographiques - une zone où s'applique un ensemble spécifique de règles pour trouver le décalage par rapport à UTC/Greenwich

En termes simples, cela résout le problème d'internationalisation que nous avions avec l'ancienne API Date. Après avoir importé java.time.ZoneId, nous pouvons examiner certaines des méthodes qu'il propose.

  • ZoneId.getAvailableZoneIds() Nous montre toutes les zones disponibles, en voici quelques-unes par exemple : Europe/Istanbul, Amérique/Eirunepe, Etc/GMT-4, Amérique/Miquelon (rappelez-vous que chacune d'entre elles est unique et nous avons deux types d'identifiants uniques qui sont répertoriés ci-dessus).
  • ZoneId.systemDefault() La méthode est définie comme « Si le fuseau horaire par défaut du système est modifié, le résultat de cette méthode changera également. » Ce qui est explicite.
  • ZoneId.of("") Nous l'utilisons pour définir un ZoneId personnalisé à partir de la liste .getAvailableZoneIds(). N'oubliez pas que UTC et Europe/Istanbul utilisés comme exemple ici peuvent être utilisés.
  • ZoneId.from() Vous vous souvenez du temporel dont nous avons parlé précédemment ? Ici, nous le passerons comme argument. Si vous n'êtes pas entièrement sûr de ce que cela fait, étant donné un ==TemporalAccessor qui représente un ensemble arbitraire d'informations de date et d'heure, nous obtiendrons un ZoneId. Si vous n'avez toujours aucune idée, vous pouvez importer java.time.ZoneId et utiliser ZonedDateTime.now() qui vous donnera une heure/date précise que vous pourrez ensuite analyser en ZoneId. Fondamentalement, ZoneId.from(ZonedDateTime.now())

Il y a aussi un argument Clock que vous pouvez transmettre, mais je n'en vois aucune utilité alors que vous pouvez simplement utiliser ZoneID mais n'hésitez pas à l'explorer

Maintenant que nous avons appris cela - Voyons la date actuelle à Paris !

LocalDate.now(ZoneId.of("Europe/Paris")) // 2024-07-10
Copier après la connexion
LocalDate.of(année, mois, jour du mois) : > Obtient une instance de LocalDate à partir d’une année, d’un mois et d’un jour.

N'oubliez pas que LocalDate représente une date. Dans ce cas, nous pouvons définir cette date sur l'année, le mois et le jour de notre choix !

LocalDate.ofYearDay(année, dayOfYear) : >

Dans de nombreux cas, vous ne disposez peut-être que d'un an et d'un jour. Cette fonction le convertit au format Année-Mois-Jour. Voici un exemple : LocalDate.ofYearDay(2023, 234) sera le 2023-08-22. Les années bissextiles seront également prises en compte.

LocalDate.parse(text) : > Obtains an instance of LocalDate from a text string using a specific format.

Basically, if we generate a String Date format like 2023-08-22 this will convert it into a LocalDate format

Epoch

There’s one last method I would like to talk about and even though it might not be that useful, it's a good thing to know.
Epoch in simple terms is a date set to the start. Virtually means it's “The start of time”. For example UNIX epoch is set to 1970/1/1 This is when all Unix time is calculated. Now this is not standardized between all computers. Most programming languages will use the UNIX epoch but not between all devices. For example NTP epoch is 1900/1/1. Now you might be asking why. And the simple answer is I don’t know. Unix was developed in 1969 and released in 71 but I guess the developers found 70 easier to work with and now that’s what we use!

LocalDate.ofEpochDay(epochDay) : >

Just going based on the description I gave about the output of this would be X days from 1970/1/1. Given epochDay is 1 => 1970-01-02 and so on.

~
~
~

By now I think you guys are all bored of all this nerdy talk and most likely lost interest completely but we are going to make it way more interesting in just a bit.
LocalDate methods have a ton of subsets to modify dates as we talked about above. Explaining all of these is just a waste of time. The best thing is for you guys to check ’em out and play around a bit, they are all very simple to understand.

Locale

The main idea of this whole article was to teach you internationalization and we are going to start that now.
If you recall above I talked about how LocalDate.now() might show different numbers/punctuations and this is standardized by Locale Class

A Locale object represents a specific geographical, political, or cultural region. An operation that requires a Locale to perform its task is called locale-sensitive and uses the Locale to tailor information for the user. For example, displaying a number is a locale-sensitive operation— the number should be formatted according to the customs and conventions of the user's native country, region, or culture.

Again the Locale class uses pre-defined ISO standards that Oracle has included.

As I said - In the early days of the web Java was rushed and we can really see that here.

Locale Constant & Why not to use

If you import java.util.Locale you can see that we have a few constants. Locale.CANADA as an example. If you're wondering what these are and why they were picked, it's quite simple. Due to the reason mentioned above, the Java devs just picked some Locale constants to support and you should not use them. Now if you look closely we have a Locale.French
and a Locale.France and you might be confused, what is this?? I’ll talk about it in a second

Now how do we go about using these Locales? By using Locale.availableLocales() you will see a large subset of available locales that you can use. you might see it in the format of en_US and you might get confused. Following up on the question listed above Java has accounted for different language subsets used in different countries. In this France/French example, We can refer to Canadian French versus French used in France. They are not entirely the same. Now a country like Iran will use Persian no matter the place, so you could just use Locale.of(language) to specify the Locale, But for French you could rather use Locale.of(language, country). Remember if you split what you got from Locale.availableLocales() by the _ you can just format it like that. An example would be Locale.of("en", "US") for en_US

Now let's implement this into our time for our different users around the globe.

System.out.println(
LocalDate.now().format(

DateTimeFormatter

.ofLocalizedDate(FormatStyle.SHORT)

.localizedBy(Locale.GERMAN)));
Copier après la connexion

Now don’t mind the extra code, and even me using Locale.GERMAN cause honestly I was looking for a different output and the easiest way was to use Javas constants. I landed on Locale.GERMAN which outputs 10.07.24 as opposed to what Japan uses (2024/07/10).

Why not use Locale.of()

Now it might sound weird, but first of all i tell you not to use constants and prefer Locale.of(), then I tell you not to use Locale.of() an important factor to consider is Locale.of() was introduced with Java 19 which goes against supporting Java 8 SE to combat that from now on we will use

new Locale.Builder()
            .setLanguage("language")
            .setRegion("country").build();
Copier après la connexion

Now another thing you could use is Locale.setDefault(language, country) which will work as well.

DateTimeFormatter

Now looking at the code above you might recall seeing DateTimeFormatter defined by docs as:

Formatter for printing and parsing date-time objects.

LocalDate.format()

As I mentioned above, one of the key features of Date/Time Local* APIs was formatting. And this is how we are going to format our dates. Looking at the code above - everything should make sense apart from the .ofLocalizedDate() method. The easiest way to show what it does is with an example.

LocalDate anotherSummerDay = LocalDate.of(2016, 8, 23);
System.out.println(DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL).format(anotherSummerDay));
System.out.println(DateTimeFormatter.ofLocalizedDate(FormatStyle.LONG).format(anotherSummerDay));
System.out.println(DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM).format(anotherSummerDay));
System.out.println(DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT).format(anotherSummerDay));
Copier après la connexion

will output the following in order:

Tuesday, August 23, 2016
August 23, 2016
Aug 23, 2016
8/23/16
Copier après la connexion

Now sometimes you might want to have your own pattern which you can easily do with

System.out.println(

LocalDate.now().format(

DateTimeFormatter

.ofPattern("dd-uuuu-MMM")));
Copier après la connexion

Now I’ll quickly go over what these symbols mean:
dd => It's a representation of the day field, now you could also use d and the difference would be that d would not have a fixed character limit since it represents 1 digit from 0-9 and 2 from 10-31. if you're lost it basically means dd would show 01; however d would show 1. However, going into two digits it's the same
uuuu/yyyy => Is the field for years. And you could also do yy which would show only the last two digits of the year. ex. 24 rather than 2024
MMM => The last field as you might have guessed is for the month - MMM tells Java that we want a String representation rather than a number. If you want a number use MM

So by now, you should’ve guessed that the output would be:

10-2024-Jul
Copier après la connexion

Instants

Now that you have a firm grip on Dates. I want to introduce you to Instants defined as:

An instantaneous point on the timeline.

Basically, this refers to Instants showing a specific moment.
By now you might have assumed that LocalDateTime has a timezone, but it doesn’t as the docs mentioned they are just a representation of date/time. However a ZoneId is in fact a representation of a time zone. Also, note that Instants don’t provide methods for altering our dates and times.

Instants capture the current moment in UTC with the Instant.now() . Now based on this, you realize that Local* really doesn’t have a meaning unless it's applied, that’s the reason why you would actually refrain from using it in a business-level application. So prefer using ZonedDateTime and Insant. As a general rule of thumb use Locale When it's a specific point on a timeline rather than a moment in time. A moment would be like the moment I publish this, or the moment you read this, or the moment the world explodes, however a point in a timeline would be like an appointment there’s no moment for an appointment. If you're going on a vacation it's a specific time on a timeline, not a moment.

Whats ZonedDateTime?

Quite simple. It's just an Instant with a ZoneId and this is why we say Insant has a timezone. No matter what you do it's not going to represent a time but rather be a specific moment.

Aigh’t well that was quite the thing, wasn’t it? phew
have a nice one >#

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

source:dev.to
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal
À propos de nous Clause de non-responsabilité Sitemap
Site Web PHP chinois:Formation PHP en ligne sur le bien-être public,Aidez les apprenants PHP à grandir rapidement!