概述: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 timepublic 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*/@Deprecatedpublic 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();//例如: 1733985453227long 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 2024return targetMillisTime;}
}
Y 推荐文献
- [Linux/MYSQL/Java] 时间与时区(UTC/GMT/CST/Timestamp) - 博客园/千千寰宇
X 参考文献