最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

使用Java構(gòu)建一個簡潔清晰的日期API

 更新時間:2025年10月29日 09:04:41   作者:sp42_frank  
這篇文章主要為大家詳細(xì)介紹了如何使用Java構(gòu)建一個簡潔清晰的日期API,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下

說起日期類型,相對其他原始數(shù)據(jù)類型(int/long/boolean/string)處理起來是比較棘手的,原因也是多方面的,首先日期是個籠統(tǒng)的概念,年月日可以說成是日期,年月日時分秒也可以說成日期,或者說單獨的時分秒也是日期,——那你到底說著哪個日期呢,是不是?Java 傳統(tǒng)日期類型java.util.Date就是這么干的,一個類型囊括上述所有的日期概念,也是造成日期 API 混亂的根源;其次日期的表達(dá)方式,也稱之為“格式 Format”,可以2025-12-22 11:05,也可以2025-12-22 11-05甚至3 Jun 2025 11:05,種類繁多;最后日期還有時區(qū)的概念,比如2024-12-03T10:15:30+01:00[Europe/Paris],Tue, 3 Jun 2025 11:05:30 GMT等等。

關(guān)于Date類型

早期 Java 版本中就是基于java.util.Date類型一統(tǒng)天下,很多日期處理方法都是圍繞它進(jìn)行的(Java 1.1 之前)。后來版本重構(gòu)中廢棄了很多的這些方法,改由java.util.Calendarjava.text.DateFormat完成。Calendar 解決了日期的棘手問題了嗎?并沒有,雖然 Calendar 處理日期起來更靈活但是使用仍然過于復(fù)雜,設(shè)置、比較、格式化仍舊比較麻煩、冗長,所以社區(qū)又有了代替品 Joda-Time,被許多項目所采用。于是這個優(yōu)秀的開源項目漸漸地成為 Java 標(biāo)準(zhǔn)的一部分,便是 JSR310,最后集成到 Java 8 中變成java.time!

總之,我們主張使用的日期類型就是java.time里面的 Instant 及 LocalDateTime,其中 Instant 表示某一時刻的時間,大致對應(yīng)時間戳,可支持納秒的級別。LocalDateTime 可能更我們更常用一些,以及它衍生的其他精確類型。

新 Java 常用日期時間類型

類型所在包Java 版本說明是否推薦
Instantjava.time.Instant8+表示時間線上的一個瞬時點(UTC),精確到納秒推薦用于時間戳
LocalDatejava.time.LocalDate8+只包含日期(年-月-日),如 2025-03-08強(qiáng)烈推薦用于“純?nèi)掌?rdquo;場景(如列車出發(fā)日)
LocalTimejava.time.LocalTime8+只包含時間(時:分:秒.納秒),如 14:30:00推薦用于“純時間”場景(如發(fā)車時間)
LocalDateTimejava.time.LocalDateTime8+日期 + 時間(無時區(qū)),如 2025-03-08T14:30:00推薦用于本地時間(如列車時刻表)
ZonedDateTimejava.time.ZonedDateTime8+帶時區(qū)的日期時間,支持夏令時等推薦用于跨時區(qū)系統(tǒng)
OffsetDateTimejava.time.OffsetDateTime8+帶偏移量的時間(如 +08:00)適合存儲數(shù)據(jù)庫時間
Durationjava.time.Duration8+表示時間段(秒、納秒),如 2 小時推薦用于計算時間差
Periodjava.time.Period8+表示時間段(年、月、日),如 1個月后推薦用于日歷周期計算
DateTimeFormatterjava.time.format.DateTimeFormatter8+線程安全的格式化/解析工具替代 SimpleDateFormat

那么 Date 類型就不用,完全廢棄了嗎?——并不是,雖然圍繞 Date 的相關(guān) API 早在 Java 1.1 之后就被廢棄,但是不代表 Date 本身被廢棄。如果廢棄了,為什么你在新版 JDK17 上找不到@Deprecated注解?說明該類型還是保留著的。作為值對象(Value Object)使用 Date 本身沒什么問題,例如兩種構(gòu)造器的用法仍保留:new Date()以及new Date(long timestamp)

API 簡介

這套筆者封裝的 日期 API,主要功能有以下三點:

  • 日期類型的轉(zhuǎn)換。面對如此繁多的日期類型:Date、Instant、Int/Long/String、LocalDate/LocalDateTime/LocalTime、ZonedDateTime 等等,給出一個相互之間都能夠轉(zhuǎn)換的方法,即輸入T 返回的日期 = input(Object anyType).to(Class<T> 期望類型)。
  • 通用的日期格式化。
  • 返回當(dāng)前日期的now()函數(shù)及其他工具函數(shù)。

源碼在:gitee.com/lightweight-components/aj-util/tree/main/aj-util/src/main/java/com/ajaxjs/util/date。

此 API屬于 aj-util 庫的一部分,而 aj-util 庫又是 aj-framework 框架的一部分,——敬請參閱了解。

萬能日期類型轉(zhuǎn)換

起初想到的轉(zhuǎn)換方式是這樣的,一個類型對應(yīng)著一個類型逐個轉(zhuǎn)換。

@SuppressWarnings("unchecked")
public <T> T to(Class<T> clz, ZoneId zoneId) {
    if (input != null) {
        if (clz == LocalDate.class) {
            LocalDate localDate = input.toInstant()
                    .atZone(zoneId == null ? ZoneId.systemDefault() : zoneId)
                    .toLocalDate();

            return (T) localDate;
        }
    }

    if (localDate != null) {
        if (clz == Date.class) {
            Date date = Date.from(localDate.atStartOfDay(zoneId == null ? ZoneId.systemDefault() : zoneId).toInstant());

            return (T) date;
        }
    }

    throw new UnsupportedOperationException("Can not transform this date type to another date type");
}

可是這樣的方式太累了,代碼也啰嗦。于是咨詢了一下 AI 的意見,改為下面清爽的代碼。

/**
 * Convert the input to the specified date type
 *
 * @param clz    The target date type
 * @param zoneId The time zone. Optional, defaults to system default if passed null
 * @param <T>    The target date type
 * @return The converted date
 */
@SuppressWarnings("unchecked")
public <T> T to(Class<T> clz, ZoneId zoneId) {
    ZoneId zone = zoneId != null ? zoneId : ZoneId.systemDefault();
    Instant baseInstant;

    if (input != null) {/* SB way, actually u can set any values to Instant by constructor or setter method */
        baseInstant = input.toInstant();
    } else if (sqlDate != null) {
        baseInstant = sqlDate.toLocalDate().atStartOfDay(zone).toInstant();
    } else if (sqlTimestamp != null) {
        baseInstant = sqlTimestamp.toInstant();
    } else if (localDate != null) {
        baseInstant = localDate.atStartOfDay(zone).toInstant();
    } else if (localDateTime != null) {
        baseInstant = localDateTime.atZone(zone).toInstant();
    } else if (zonedDateTime != null) {
        baseInstant = zonedDateTime.toInstant();
    } else if (offsetDateTime != null) {
        baseInstant = offsetDateTime.toInstant();
    } else if (offsetTime != null) {
        baseInstant = offsetTime.atDate(LocalDate.now()).toInstant();
    } else if (instant != null) {
        baseInstant = instant;
    } else if (timestamp != 0L) {
        baseInstant = Instant.ofEpochMilli(timestamp);
    } else
        throw new UnsupportedOperationException("No input date/time set.");

    // Convert baseInstant to target
    if (clz == Instant.class) {
        return (T) baseInstant;
    } else if (clz == Date.class) {
        return (T) Date.from(baseInstant);
    } else if (clz == java.sql.Date.class) {
        return (T) java.sql.Date.valueOf(baseInstant.atZone(zone).toLocalDate());
    } else if (clz == Timestamp.class) {
        return (T) Timestamp.from(baseInstant);
    } else if (clz == LocalDate.class) {
        return (T) baseInstant.atZone(zone).toLocalDate();
    } else if (clz == LocalTime.class) {
        return (T) baseInstant.atZone(zone).toLocalTime();
    } else if (clz == LocalDateTime.class) {
        return (T) baseInstant.atZone(zone).toLocalDateTime();
    } else if (clz == ZonedDateTime.class) {
        return (T) baseInstant.atZone(zone);
    } else if (clz == OffsetDateTime.class) {
        return (T) baseInstant.atOffset(zone.getRules().getOffset(baseInstant));
    } else if (clz == OffsetTime.class) {
        return (T) baseInstant.atZone(zone).toOffsetDateTime().toOffsetTime();
    } else if (clz == Calendar.class) {
        Calendar calendar = Calendar.getInstance();
        baseInstant.atZone(zone);
        calendar.setTimeInMillis(baseInstant.toEpochMilli());

        return (T) calendar;
    }

    throw new UnsupportedOperationException("Unsupported target type: " + clz.getName());
}

主要就是不管什么輸入類型,先統(tǒng)一轉(zhuǎn)換到Instant類再轉(zhuǎn)為目標(biāo)類型。

下面是一些用法例子:

long timestamp = System.currentTimeMillis();
Instant expected = Instant.ofEpochMilli(timestamp);

Instant result = new DateTypeConvert(timestamp).to(Instant.class, null);
assertEquals(expected, result);


Instant instant = Instant.now();
LocalDateTime expected = instant.atZone(zone).toLocalDateTime();

LocalDateTime result = new DateTypeConvert(instant).to(LocalDateTime.class, null);
assertEquals(expected, result);

LocalDate localDate = LocalDate.of(2025, 10, 23);
Date expected = Date.from(localDate.atStartOfDay(zone).toInstant());

Date result = new DateTypeConvert(localDate).to(Date.class, null);
assertEquals(expected, result);

日期格式化

新版推薦使用DateTimeFormatter替代SimpleDateFormat,使之線程安全與 API 清晰。同時DateTimeFormatter.ofPattern()實例有一定開銷,尤其是自定義模式(如 "yyyy-MM-dd HH:mm:ss"),于是我們可以緩存 DateTimeFormatter 實例的方式來優(yōu)化。

Formatter 用法如下:

new Formatter(TemporalAccessor temporal).format();
new Formatter(TemporalAccessor temporal).format(String format)

接口TemporalAccessor實現(xiàn)都是常見的那些日期類型,于是我們在構(gòu)造器傳入即可,然后指定日期格式的字符串。

工具函數(shù)

主要是now()返回當(dāng)前時間字符串的工具函數(shù)。

/**
 * Obtain current time by specified format.
 *
 * @param formatter The formatter object
 * @return The current time
 */
public static String now(DateTimeFormatter formatter) {
    return LocalDateTime.now().format(formatter);
}

/**
 * Obtain current time by specified format.
 *
 * @param format The format string
 * @return The current time
 */
public static String now(String format) {
    return now(Formatter.getDateFormatter(format));
}

/**
 * Obtain current time, which is formatted by default like "yyyy-MM-dd HH:mm:ss".
 *
 * @return The current time
 */
public static String now() {
    return now(Formatter.getDateTimeFormatter());
}

/**
 * Obtain current time, which is formatted like "yyyy-MM-dd HH:mm".
 *
 * @return The current time
 */
public static String nowShort() {
    return now(Formatter.getDateTimeShortFormatter());
}

/**
 * 請求的時間戳,格式必須符合 RFC1123 的日期格式
 *
 * @return The current time
 */
public static String nowGMTDate() {
    return Formatter.GMT_FORMATTER.format(Instant.now());
}

/**
 * 請求的時間戳。按照 ISO8601 標(biāo)準(zhǔn)表示,并需要使用 UTC 時間,格式為 yyyy-MM-ddTHH:mm:ssZ
 *
 * @return The current time
 */
public static String newISO8601Date() {
    return Formatter.ISO8601_FORMATTER.format(Instant.now());
}

另外還包括一個字符串轉(zhuǎn)日期的函數(shù),其主要使用正則來匹配是否日期字符串然后進(jìn)行轉(zhuǎn)換。

小結(jié)

這套 API 原理并不是太復(fù)雜,主要是通過封裝來厘清 Java 日期 API 的使用,務(wù)求更簡單、清晰。

到此這篇關(guān)于使用Java構(gòu)建一個簡潔清晰的日期API的文章就介紹到這了,更多相關(guān)Java構(gòu)建日期API內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 智能手表開發(fā)API接口

    智能手表開發(fā)API接口

    這篇文章主要介紹了智能手表開發(fā)API接口,使用圖靈機(jī)器人平臺接口實現(xiàn)天氣預(yù)報,非常簡單實用,這里推薦給大家。
    2015-03-03
  • 淺談Java中格式化輸出

    淺談Java中格式化輸出

    這篇文章主要介紹了Java中格式化輸出,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04
  • spring aop兩種配置方式

    spring aop兩種配置方式

    這篇文章主要為大家詳細(xì)介紹了spring aop兩種配置方式,主要是注解配置AOP和xml配置aop,需要的朋友可以參考下
    2015-09-09
  • java web將數(shù)據(jù)導(dǎo)出為pdf格式文件代碼片段

    java web將數(shù)據(jù)導(dǎo)出為pdf格式文件代碼片段

    這篇文章主要為大家詳細(xì)介紹了java web將數(shù)據(jù)導(dǎo)出為pdf格式文件代碼片段,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-01-01
  • Spring中@Autowired和@Resource注解的使用區(qū)別詳解

    Spring中@Autowired和@Resource注解的使用區(qū)別詳解

    這篇文章主要介紹了Spring中@Autowired和@Resource注解的使用區(qū)別詳解,@Autowired默認(rèn)根據(jù)type進(jìn)行注入,找到與指定類型兼容的?Bean?并進(jìn)行注入,如果無法通過type匹配到對應(yīng)的?Bean?的話,會根據(jù)name進(jìn)行匹配,如果都匹配不到則拋出異常,需要的朋友可以參考下
    2023-11-11
  • intellij IDEA配置springboot的圖文教程

    intellij IDEA配置springboot的圖文教程

    Spring Boot是由Pivotal團(tuán)隊提供的全新框架,其設(shè)計目的是用來簡化新Spring應(yīng)用的初始搭建以及開發(fā)過程。接下來通過本文給大家介紹intellij IDEA配置springboot的圖文教程,感興趣的朋友一起看看吧
    2018-03-03
  • MybatisPlus自帶的queryWrapper實現(xiàn)時間倒序方式

    MybatisPlus自帶的queryWrapper實現(xiàn)時間倒序方式

    這篇文章主要介紹了MybatisPlus自帶的queryWrapper實現(xiàn)時間倒序方式,具有很好的參考價值,希望對的有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-01-01
  • 一文詳解Java中的原子操作

    一文詳解Java中的原子操作

    在Java中,原子操作尤為重要,尤其是在多線程環(huán)境中,想象一下,如果小黑在操作一個共享變量時,這個操作被其他線程打斷,那會發(fā)生什么?可能會導(dǎo)致數(shù)據(jù)不一致,或者更糟糕的情況,本文將給大家詳細(xì)介紹一下Java中的原子操作
    2024-01-01
  • java使用Socket實現(xiàn)文件上傳功能

    java使用Socket實現(xiàn)文件上傳功能

    這篇文章主要為大家詳細(xì)介紹了java使用Socket實現(xiàn)文件上傳功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • SpringCloud之Zuul網(wǎng)關(guān)原理及其配置講解

    SpringCloud之Zuul網(wǎng)關(guān)原理及其配置講解

    這篇文章主要介紹了SpringCloud之Zuul網(wǎng)關(guān)原理及其配置講解,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-03-03

最新評論

黑山县| 蛟河市| 当雄县| 镇雄县| 吴桥县| 化德县| 辽宁省| 黎平县| 黄梅县| 阳东县| 霍山县| 长宁区| 淳化县| 钦州市| 句容市| 延吉市| 乌审旗| 仪陇县| 山阴县| 濮阳县| 剑川县| 安图县| 同江市| 宁乡县| 射洪县| 赤峰市| 德化县| 大荔县| 湖口县| 长垣县| 彭泽县| 象山县| 集贤县| 额敏县| 民权县| 民县| 兴安县| 南华县| 麻城市| 临高县| 饶平县|