[Java/日期/时间/时区] Java 时间的转换与处理:DateTimeUtils

1 概述:Java 时间的转换与处理

深入理解:Date / Calendar / Timestamp / TimeZone

  • java.util.Date / java.sql.Timestamp : 基于时间戳(Long)构建,与时区无关
  • java.util.Calendar: 基于时间字符串(String)构建,与时区强依赖
  • java.text.SimpleDateFormat : 与时区强依赖
  • java.util.TimeZone : 时区对象

Z 最佳实践

DateTimeUtils

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;

/**
 * @updateTime 2025-09-10 23:28
 * @description
 * @reference-doc
 *  [1] java 不同时区转换 - CSDN - https://blog.csdn.net/qq_41344974/article/details/125505290
 */
public class DatetimeUtils {
    private final static Logger logger = LoggerFactory.getLogger(DatetimeUtils.class);

    /** 毫秒级时间字符串 millisecond time format **/
    public final static String MILLISECOND_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss.SSS";
    public final static String MILLISECOND_TIME_WITH_NUMBER_FORMAT = "yyyyMMddHHmmssSSS";


    /**
     * 时区ID
     * @sample-values 可选值
     *  "Asia/Shanghai" / "UTC" / "GMT" / ...
     * @note
     * "Asia/Shanghai" = "CST" (China Standard Time) = GMT+8 = UTC+8
     */
    public final static String zoneId = "UTC";
    //public final static TimeZone time

    public static String calendarToString(Calendar calendar, String format, TimeZone targetTimeZone){
        SimpleDateFormat sdf = new SimpleDateFormat(format); //such as: "yyyy-MM-dd"
        sdf.setTimeZone( targetTimeZone );
        return sdf.format(calendar.getTime());//时间戳转指定时区的时间字符串
    }

    public static Calendar stringToCalendar(String dateStr,String format, TimeZone timeZone) throws ParseException {
        SimpleDateFormat sdf= new SimpleDateFormat(format); //such as:"yyyy-MM-dd"
        sdf.setTimeZone( timeZone );
        Date date = sdf.parse(dateStr);
        return dateToCalendar(date, timeZone);
    }

    /**
     * 时间戳 转 Date
     * @note
     *   1. {@link Date } 底层存储与维护的是 long (时间戳)
     *   2. 基于第1点,未涉及时区
     * @param time 13位的毫秒级时间戳 eg: 1503544630000L
     * @return
     */
    public static Date longToDate(long time){
        return new Date(time);
    }

    public static Calendar longToCalender(long time, TimeZone timeZone){
        return dateToCalendar( longToDate(time), timeZone );
    }

    public static Long calenderToLong(Calendar calendar){
        return calendarToTimestamp(calendar).getTime();
    }

    /**
     *
     * @param time
     *  eg:
     *      1665211423751L
     * @param format
     *  eg:
     *      "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"
     * @return
     *  eg:
     *      "2022-10-08T14:43:43.751Z"
     */
    public static String longToString(long time, String format, TimeZone timeZone){
        return calendarToString( longToCalender(time, timeZone), format, timeZone );
    }

    /**
     *
     * @param datetimeStr 当前应用的时间字符串
     *  eg:
     *      "2022-10-06 11:49:00"
     *      "2022-10-06 11:49"
     *      "2022-10-08T07:01:40.751Z"
     * @param format
     *  eg:
     *      "yyyy-MM-dd hh:mm:ss"
     *      "yyyy-MM-dd hh:mm"
     *      "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'" | T代表可替换的任意字符, Z 代表时区
     * @param timeZone [选填参数] 允许为 null
     *  可选值有:
     *      "UTC" / "Asia/Shanghai" / "GMT" / "GMT+08:00" / ...
     * @return
     *  eg:
     *      1665028140000L
     *      1665028140000L
     *      1665212500751L [timeZone=UTC] 1665183700751L [timeZone=null]
     * @reference-doc
     *  [1] java 不同时区转换 - CSDN - https://blog.csdn.net/qq_41344974/article/details/125505290
     */
    public static long stringToLong(String datetimeStr, String format, String timeZone) {
        SimpleDateFormat formatSDF = new SimpleDateFormat(format);// such as "yyyyMMddhhmmss"
        //new SimpleDateFormat(format, Locale.getDefault());// such as "yyyyMMddhhmmss"
        if(! StringUtils.isEmpty(timeZone) ){
            formatSDF.setTimeZone(TimeZone.getTimeZone(timeZone));
        }
        Date date = null;
        try {
            date = formatSDF.parse(datetimeStr);
            return date.getTime();
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return -1;
    }

    public static long stringToLong(String datetimeStr, String format, TimeZone timeZone) {
        return stringToLong(datetimeStr, format, timeZone);
    }

    public static String dateToString(Date date, String format, TimeZone timeZone){
        SimpleDateFormat sdf= new SimpleDateFormat(format); //such as:"yyyy-MM-dd"
        sdf.setTimeZone(timeZone);
        return sdf.format(date);
    }

    public static Date stringToDate(String dateStr, String formatOfStr, TimeZone timeZone) throws ParseException {
        //dateStr such as :"2018-11-4"
        SimpleDateFormat sdf = new SimpleDateFormat(formatOfStr);//such as:"yyyy-MM-dd"
        sdf.setTimeZone( timeZone );
        return sdf.parse(dateStr);
    }

    /**
     * Date 转 Calendar
     * @note
     *   1. 此转换过程,因涉及 {@link Calendar } 涉及时区
     * @param date
     * @return
     */
    @Deprecated
    public static Calendar dateToCalendar(Date date){
        Calendar calendar = Calendar.getInstance();//等效于: createCalendar(TimeZone.getDefault(), Locale.getDefault(Category.FORMAT));
        calendar.setTime(date);
        return calendar;
    }

    public static Calendar dateToCalendar(Date date, TimeZone timeZone){
        Calendar calendar = Calendar.getInstance( timeZone );//createCalendar(TimeZone.getDefault(), Locale.getDefault(Category.FORMAT));
        calendar.setTime(date);
        return calendar;
    }

    public static Date calendarToDate(Calendar calendar){
        Date date = calendar.getTime();
        return date;
    }

    public static Timestamp stringToTimestamp(String dateStr,String dateFormat, TimeZone timeZone) throws ParseException {
        //dateStr such as:"2019-1-14 08:11:00"
        Calendar calendar = stringToCalendar(dateStr, dateFormat, timeZone);
        Timestamp timestamp = new Timestamp( calendar.getTimeInMillis() );
        //Timestamp timestamp = Timestamp.valueOf(dateStr);
        return timestamp;
    }

    public static String timestampToString(Timestamp timestamp, String format, TimeZone timeZone){
        SimpleDateFormat sdf= new SimpleDateFormat(format);//such as:"yyyy-MM-dd"
        sdf.setTimeZone( timeZone );
        return sdf.format(timestamp);
    }

    public static Timestamp dateToTimestamp(Date date){
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Timestamp timestamp = new Timestamp( date.getTime() );
        //Timestamp timestamp = Timestamp.valueOf(df.format(date));
        return timestamp;
    }

    public static Calendar timestampToCalendar(Timestamp timestamp, TimeZone timeZone){
        Calendar calendar = Calendar.getInstance(timeZone);
        calendar.setTime(timestamp);
        return calendar;
    }
    public static Timestamp calendarToTimestamp(Calendar calendar){
        return dateToTimestamp( calendarToDate(calendar) );
    }

    public static String millisecondToDateString(long ms){
        Integer ss = 1000;
        Integer mi = ss * 60;
        Integer hh = mi * 60;
        Integer dd = hh * 24;

        Long day = ms / dd;
        Long hour = (ms - day * dd) / hh;
        Long minute = (ms - day * dd - hour * hh) / mi;
        Long second = (ms - day * dd - hour * hh - minute * mi) / ss;

        StringBuffer sb = new StringBuffer();
        if(day >= 0) {
            sb.append(day+"day");
        }
        if(hour >= 0) {
            sb.append(hour+"hour");
        }
        if(minute >= 0) {
            sb.append(minute+"minute");
        }
        if(second >= 0) {
            sb.append(second+"second");
        }
        return sb.toString();
    }

    /**
     * 纳秒数转毫秒级时间戳
     * @param targetNanoTime
     *   eg: long targetNanoTime = System.nanoTime(); // 获取当前时间的 nano time,例如 : 87277522042200
     * @return
     */
    public static long nanoTimeToMillisTimestamp(long targetNanoTime){
        //待转换的纳秒时间(targetNanoTime)
        //long targetNanoTime = System.nanoTime(); // 获取当前时间的 nano time,例如 : 87277522042200

        //获取当前的毫秒数(currentTimeMillis) 和 纳秒数(currentNanoTime)
        long currentTimeMillis = System.currentTimeMillis();//例如: 1733985453227
        long currentNanoTime = System.nanoTime();//例如 : 87277522044200

        //计算 currentNanoTime 与 targetNanoTime 的差值(nanoTimeDiff)
        long nanoTimeDiff = currentNanoTime - targetNanoTime;//例如: 2000
        // 利用 currentNanoTime 和 nanoTimeDiff ,向前推算出 targetNanoTime当时对应的毫秒级时间戳
        long targetMillisTime = currentTimeMillis - ( nanoTimeDiff / 1000000L);//13位的毫秒级时间戳,例如: 1733985453227

        //Date date = new Date(targetMillisTime); // 创建日期对象
        //System.out.println("date : " + date.toString());//例如: date : Thu Dec 12 14:37:33 CST 2024
        return targetMillisTime;
    }
}

Y 推荐文献

  1. 是不是Date对象里存了【年月日时分秒】呢?不是的,【Date对象】里存的只是一个【long】型的变量,其值为UTC+0时区、自【1970年1月1日0点】至Date对象所记录时刻经过的毫秒数
  2. 时间戳与 Date对象的转换: Date date = new Date(1503544630000L); Long timestamp = date.getTime();
  3. 时区:全球分为24个时区,相邻时区时间相差1个小时。

X 参考文献

posted @ 2025-09-10 23:34  千千寰宇  阅读(41)  评论(0)    收藏  举报