”工欲善其事,必先利其器。“—孔子《论语.录灵公》
首页 > 编程 > 让我们正确地进行日期

让我们正确地进行日期

发布于2024-11-04
浏览:618

Lets do dates properly

As a beginner one of the most interesting topics you’ll learn are Dates. Even though it might sound a bit boring, it's one of the key things you might know; from your Database, API, GUI, and more learning how to deal with dates properly is a key factor in writing good applications.

Before we start

An important detail you must remember is Java was rushed for the web, thus you have a lot of quirky and somewhat stupid ways to do stuff. The goal of this guide will be to teach you how to use the latest Java APIs to write efficient good code. I’ll aim to teach you how not to code anything hard and rather use standardized ISO for a scalable application.

How to work with Dates

The Date API

As of Java 8 SE with the release of the Date Class defined as:

The class Date represents a specific instant in time, with millisecond precision.

Also further on we had the addition of the Abstract Calender Class (with significant upgrade with JDK 1.1) defined as:

The Calendar class is an abstract class that provides methods for converting between a specific instant in time and a set of calendar fields such as YEAR, MONTH, DAY_OF_MONTH, HOUR, and so on, and for manipulating the calendar fields, such as getting the date of the next week. An instant in time can be represented by a millisecond value that is an offset from the Epoch, January 1, 1970 00:00:00.000 GMT (Gregorian).

As noted by the Oracle docs the reason was the lack of internationalization abilities.

It’s good to note that the same documentation linked above goes into further detail about its timing if it interests you.

The LocalDate API

Also with Java 8 SE came the LocalDate Class which is referred to:

A date without a time-zone in the ISO-8601 calendar system, such as 2007-12-03.
LocalDate is an immutable date-time object that represents a date, often viewed as year-month-day. Other date fields, such as day-of-year, day-of-week and week-of-year, can also be accessed. For example, the value "2nd October 2007" can be stored in a LocalDate.

An important specification to take note of is:

This class does not store or represent a time or time zone. Instead, it is a description of the date, as used for birthdays. It cannot represent an instant on the timeline without additional information such as an offset or time zone.

Difference & Which one to use

Issues with the Date/Time API’s

Further reading the LocalDate class will lead you to “This class is immutable and thread-safe.” This brings us to our first problem.

  • Both the Date and Calender were not thread-safe. If you're a bit confused as to what it means - Threads are a way to implement concurrency with a computer application this allows for multiple tasks to be running concurrently rather than sequentially (If you have a programming background you can see this as async).
  • Another issue with the Date/Calender API was its poor design. Later on, it was revamped to be ISO-centric (If you are a bit lost on what this whole ISO thing is; in short ISO stands for “International Organization for Standardization”) And we will see the added benefits of this later on.
  • And lastly coming back to the lack of internationalization was that developers were required to write their logic for handling different time zones which can result in a lot of faults as miss-matches.

The actual difference

The biggest difference is despite the name Date would store both time and date (as mentioned by the docs with millisecond offset since epoch - we’ll talk about epoch later on). With the newer API, we get access to easier Formatting/Parsing/Manipulation of Dates.

What if I want to store time as well?

Well Java has you covered there as well with their LocalDateTime Class

A date-time without a time-zone in the ISO-8601 calendar system, such as 2007-12-03T10:15:30.
LocalDateTime is an immutable date-time object that represents a date-time, often viewed as year-month-day-hour-minute-second. Other date and time fields, such as day-of-year, day-of-week and week-of-year, can also be accessed. Time is represented by nanosecond precision. For example, the value "2nd October 2007 at 13:45.30.123456789" can be stored in a LocalDateTime.

If you would only want to store time then you can use the LocalTime Class

Quick little recap and use cases

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

LocalDate

Now that we have a good understanding of its background and what we can do with it, let's explore the methods of the LocalDate class.

ISO 8601

The ISO-8601 calendar system is the modern civil calendar system used today in most of the world. It is equivalent to the proleptic Gregorian calendar system, in which today's rules for leap years are applied for all time. For most applications written today, the ISO-8601 rules are entirely suitable. However, any application that makes use of historical dates, and requires them to be accurate will find the ISO-8601 approach unsuitable.

This is the standard Java will use to properly format our dates.

Temporal

Before we do a deep dive I want to introduce you to the Temporal object which all of the new Date APIs implement (LocalDate, LocalTime, LocalDateTime) it's defined as:

This is the base interface type for date, time, and offset objects that are complete enough to be manipulated using plus and minus. It is implemented by those classes that can provide and manipulate information as fields or queries. See TemporalAccessor for the read-only version of this interface.

Not going into depth into this just wanted you guys to understand what this is if you encounter it.

Methods

The format for this will be in order - The method name, the specified return description, and a quick summary of what it does/or an in-depth dive. If you want to follow along I’m going to use jshell just import java.time.LocalDate and copy the same methods.

LocalDate.now(): > the current date using the system clock and default time-zone, not null

As mentioned by the description it will return the current date format based on time zone as example for me it gives 2024-07-10 however the format might change based on your locale time dependent on the ISO 8601 format assigned for your country (ex. it might be 2024.07.10 or 24/7/10 this is a standard that your country would use)

The LocalDate.now() method can take an argument. To use this we will import java.time.ZoneId.

What is ZoneId?

ZoneId Released with Java 8SE defined as:

A ZoneId is used to identify the rules used to convert between an Instant and a LocalDateTime. There are two distinct types of ID:

  • Fixed offsets - a fully resolved offset from UTC/Greenwich, that uses the same offset for all local date-times
  • Geographical regions - an area where a specific set of rules for finding the offset from UTC/Greenwich apply

In simple terms, this resolves the internationalization issue we had with the old Date API. After importing java.time.ZoneId we can look at some of the methods it has to offer.

  • ZoneId.getAvailableZoneIds() Shows us all available zones here are some for example: Europe/Istanbul, America/Eirunepe, Etc/GMT-4, America/Miquelon (Remember each one of these is unique and we have two types of unique ID’s which are listed above).
  • ZoneId.systemDefault() The method is defined as “If the system default time-zone is changed, then the result of this method will also change.” Which is self-explanatory.
  • ZoneId.of("") We use this to define a custom set ZoneId from the .getAvailableZoneIds() list. Remember both UTC and Europe/Istanbul used as an example here can be used.
  • ZoneId.from() Remember the temporal we talked about before? Here we will pass it as an argument. If you're not entirely sure what this does, given a ==TemporalAccessor which represents an arbitrary set of date and time information we’ll get a ZoneId. If you are still a bit clueless you can import java.time.ZoneId and use ZonedDateTime.now() which will give you a precise time/date which then you could parse to a ZoneId. Basically ZoneId.from(ZonedDateTime.now())

There also a Clock argument you can pass, but I don’t see any use for it when you could just use ZoneID but feel free to explore that

Now that we learned that - Let’s get the current date in Paris!

LocalDate.now(ZoneId.of("Europe/Paris")) // 2024-07-10
LocalDate.of(year, month, day of month): > Obtains an instance of LocalDate from a year, month, and day.

Remember LocalDate represents a Date. In this case, we can set that date to whatever year,month, and day we want!

LocalDate.ofYearDay(year, dayOfYear): >

In a lot of cases, you might only have a year and a day. This function converts it to a Year-Month-Day format. Here’s an example LocalDate.ofYearDay(2023, 234) will be 2023-08-22. Leap years will also be accounted for.

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)));

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();

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));

will output the following in order:

Tuesday, August 23, 2016
August 23, 2016
Aug 23, 2016
8/23/16

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")));

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

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 >#

版本声明 本文转载于:https://dev.to/ry44n__/lets-do-dates-properly-4e2o?1如有侵犯,请联系[email protected]删除
最新教程 更多>
  • 如何在 Python 中创建虚拟环境
    如何在 Python 中创建虚拟环境
    Python 虚拟环境对于管理依赖关系和避免项目之间的冲突至关重要。本指南将引导您完成在 Python 中创建和激活虚拟环境的过程。 第 1 步:导航到您的项目目录 打开终端并导航到要设置 Python 虚拟环境的目录。您可以使用 cd 命令来执行此操作: cd /path/to/y...
    编程 发布于2024-11-08
  • 如何在 Go JSON 解组中处理嵌套数组?
    如何在 Go JSON 解组中处理嵌套数组?
    Golang JSON:通过解组处理嵌套数组在 Go 中,在解组后处理嵌套 JSON 数组时,理解错误至关重要“类型接口{}不支持索引。”当您尝试访问存储在interface{}变量中的JSON数组中的元素时,会出现此错误。要解决此问题,您需要利用类型断言将interface{}变量转换为底层数组类...
    编程 发布于2024-11-08
  • 如何在 Java 中组合路径
    如何在 Java 中组合路径
    组合 Java 中的路径C#/.NET 中的 System.IO.Path.Combine 方法允许将多个路径段组合成一个单一、有效的路径。 Java 提供了实现类似功能的替代方法。Path Object在 Java 7 及更高版本中,建议使用 java.nio.file.Path 类进行路径操作。...
    编程 发布于2024-11-08
  • 有效 JSON 有哪些不同的定义?
    有效 JSON 有哪些不同的定义?
    理解最小有效 JSONJSON 的概念已在各种 RFC 和规范中广泛讨论。 RFC4627 最初将 JSON 定义为序列化对象或数组。根据此定义,仅 {}(空对象) 和 [](空数组) 符合有效、完整的 JSON 字符串的条件。但是,ECMA-404引入了一项修正案,扩大了有效 JSON 字符串的范...
    编程 发布于2024-11-08
  • 使用 MapStruct 映射继承层次结构
    使用 MapStruct 映射继承层次结构
    Intro MapStruct provides a rich set of features for mapping Java types. The technical documentation describes extensively the classes and ann...
    编程 发布于2024-11-08
  • 可以处理变量的 ID 以访问 Python 中的对象吗?
    可以处理变量的 ID 以访问 Python 中的对象吗?
    变量的 ID 可以取消引用吗?在 Python 中,id() 函数返回对象的唯一标识符。这个标识符可以存储在变量中,但是这个变量的ID可以解引用吗?从学术角度来看,答案是肯定的。 _ctypes 模块提供了一个函数 PyObj_FromPtr(),可以将指针转换为 Python 对象。使用此函数,我...
    编程 发布于2024-11-08
  • 为什么 imagecreatefrompng() 产生黑色背景而不是透明区域?
    为什么 imagecreatefrompng() 产生黑色背景而不是透明区域?
    imagecreatefrompng() 生成黑色背景而不是透明区域?在 PHP 中,imagecreatefrompng() 函数通常用于处理 PNG图像。然而,据观察,使用此函数时,PNG 透明度可能会转换为纯黑色。要解决此问题,可以在使用 imagecreatetruecolor() 创建新画...
    编程 发布于2024-11-08
  • Go反射中reflect.Type和reflect.Value的主要区别是什么?
    Go反射中reflect.Type和reflect.Value的主要区别是什么?
    Go 中的反射类型和值Go 中的反射允许开发人员在运行时检查和操作类型和值。了解它们的区别对于有效使用反射至关重要。反射中的类型与值在反射中,reflect.TypeOf(i) 返回一个reflect.Type 对象,而reflect.ValueOf(i)返回一个reflect.Value obje...
    编程 发布于2024-11-08
  • 如何在 AngularJS 中安全地设置变量的 iframe src 属性?
    如何在 AngularJS 中安全地设置变量的 iframe src 属性?
    在 AngularJS 中从变量设置 iframe src 属性在 AngularJS 中,尝试从以下位置设置 iframe 的 src 属性时可能会遇到问题一个变量。为了解决这个问题,这里有一个分步指南:1。注入 $sce 服务将 $sce(严格上下文转义)服务注入控制器以处理清理。functio...
    编程 发布于2024-11-08
  • 为什么我的 KeyListener 无法在 JPanel 中工作?
    为什么我的 KeyListener 无法在 JPanel 中工作?
    JPanel 中 KeyListeners 无响应:常见问题当使用 KeyListeners 检测 JPanel 中的击键时,开发人员经常遇到这样的问题:侦听器无法触发所需的操作。此问题可能由多个因素引起。焦点组件约束KeyListener 依赖将自身附加到焦点组件才能正常运行。默认情况下,焦点不会...
    编程 发布于2024-11-08
  • 从 React 到 React Native 的旅程
    从 React 到 React Native 的旅程
    作为一名 React / JS 开发人员,您可能有这样的想法 “我应该学习 React Native 吗?” 这是一个公平的问题,也是我几年前问自己的问题。事实证明,学习 React Native 绝对是正确的决定。这让我成为了亚马逊的高级开发倡导者,我现在使用 React Native 跨 And...
    编程 发布于2024-11-08
  • 使用 Filament 和 Laravel 构建强大的管理面板:分步指南
    使用 Filament 和 Laravel 构建强大的管理面板:分步指南
    Laravel 是一个强大的 PHP 框架,为开发 Web 应用程序提供了坚实的基础。 Filament 是一个开源、优雅的 Laravel 管理面板和表单构建器,可简化管理界面的创建。本指南将引导您使用最新版本的 Filament 和 Laravel 构建强大的管理面板。 Laravel SaaS...
    编程 发布于2024-11-08
  • 如何从 Pandas DataFrame 中提取列标题?
    如何从 Pandas DataFrame 中提取列标题?
    从 Pandas DataFrame 中检索列标题Pandas DataFrame 是通用的数据结构,可以实现高效的数据操作和分析。一项常见任务涉及提取列标题,这对于获取 DataFrame 结构的概述或进一步处理非常有用。假设您有一个从用户输入导入的 DataFrame,其中列的数量和名称未知。要...
    编程 发布于2024-11-08
  • 通过示例解释 Web 存储 API
    通过示例解释 Web 存储 API
    Web Storage API: বিস্তারিত আলোচনা Web Storage API হলো জাভাস্ক্রিপ্টের একটি শক্তিশালী API যা ব্রাউজারে ব্যবহারকারীর ডেটা স্টোর করার জন্য ব্যবহ...
    编程 发布于2024-11-08
  • 使用 Web 工具进行 Android 开发:使用 Ionic React 进行生产的最快方式
    使用 Web 工具进行 Android 开发:使用 Ionic React 进行生产的最快方式
    Investing in Android development can yield a huge device market share, expanded market reach, and high return on investment. With over 6.8 billion sma...
    编程 发布于2024-11-08

免责声明: 提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发到邮箱:[email protected] 我们会第一时间内为您处理。

Copyright© 2022 湘ICP备2022001581号-3