DateUtil,时区,常用的日期接口

背景

这期总结了Java中常用的关于日期和时间的接口,代码在后面的 DateUtil 类中。顺便讨论了一下时区。文章尽量做到精简

表示时间的形式

在 Java 里,表示时间通常有3种形式

  • 时间戳
  • Date (java.util.Date)
  • 字符串

(不讨论LocalDateTime之类的)

例如

  • 时间戳: System.currentTimeMillis() 的值
  • Date:你经常 new Date()
  • 字符串: 比如 2015-04-04 16:22:01,或者 2015-04-04

关于时区

上述3种情况

  • 时间戳是不带时区的

    时间戳是绝对的值,是当前这一刻(无论你在什么时区) 距离零时区1970年1月1日的毫秒数,所以时间戳是没有时区的

  • new Date() (java.util.Date) 也是没有时区概念的

    Date其里面存放的值是 System.currentTimeMillis() ,但是 toString() 方法会根据本地时区(即操作系统的时区)转成相应的字串,其本身是不带时区的!! 这点太容易混淆

    SimpleDateFormat 是我们常用的类,用来把 Date 格式化成时间字符串,这个是可以设定时区的,Date 本身没有时区,要得到指定时区的时间字符串,需要对 SimpleDateFormat 设置时区 sdf.setTimeZone(TimeZone zone);

  • 日期格式的字符串

    是有时区的,比如 2015-04-04 16:22:01,或者 2015-04-04,这些表示方法都是没有时区概念

附录

附 DateUtil.java

/*** @author Stone* @version V1.0.0* @date 2021/3/18*/
public class DateUtil {/*** 常用时间格式*/public static final String Y_M_D_H_M_S = "yyyy-MM-dd HH:mm:ss";public static final String Y_M_D = "yyyy-MM-dd";public static final String YMD = "yyyyMMdd";public static final String Y_M_D_H_M_S_SSS = "yyyy-MM-dd HH:mm:ss.SSS";//public static final String DATE_FORMAT_UTC_TEMPLATE = "yyyy-MM-dd'T'HH:mm:ss'Z'";//public static final String DATE_FORMAT_UTC_TEMPLATE = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";/*** 常用时区*/public static class TZ {public static final TimeZone UTC = TimeZone.getTimeZone("GMT+00:00");public static final TimeZone BEIJING = TimeZone.getTimeZone("GMT+08:00");public static final TimeZone TOKYO = TimeZone.getTimeZone("GMT+09:00");public static final TimeZone LOCAL = localTimeZone();}/*** 获取本地时区(指当前的时区,即Java程序所在JVM,JVM所在的操作系统的时区)** @return 本地时区*/public static TimeZone localTimeZone() {return TimeZone.getDefault();}/************************************ 时间类型互转,字串,Date,long BEGIN ************************************//*** 时间戳转字串(本地时区)** @param timestampWithMillis 时间戳,精确到毫秒,例如 System.currentTimeMillis() 的值* @param destDateFormat      要转成什么样的字串格式* @return 本地时区的日期时间的字串形式*/public static String long2Str(long timestampWithMillis, String destDateFormat) {return long2StrTz(timestampWithMillis, destDateFormat, localTimeZone());}public static String long2StrUTC(long timestampWithMillis, String destDateFormat) {return long2StrTz(timestampWithMillis, destDateFormat, TZ.UTC);}/*** 时间戳转字串(指定时区)** @param timestampWithMillis 时间戳,精确到毫秒,例如 System.currentTimeMillis() 的值* @param destDateFormat      要转成什么样的字串格式* @param destTimeZone        目的时区,即时间戳要转成什么时区。参考本类中定义的常用时区。* @return 指定时区的日期时间的字串形式*/public static String long2StrTz(long timestampWithMillis, String destDateFormat, TimeZone destTimeZone) {SimpleDateFormat sdf = new SimpleDateFormat(destDateFormat);sdf.setTimeZone(destTimeZone);return sdf.format(timestampWithMillis);}/*** 时间戳转 Date** <pre>* 注意:Date 是没有时区概念的,其内部保存了时间戳,toString() 时根据本地时区转成字串而已* </pre>** @param timestampWithMillis 时间戳,到达毫秒级,如 System.currentTimeMillis()* @return 返回 java.util.Date*/public static Date long2Date(long timestampWithMillis) {Date date = new Date(timestampWithMillis);return date;}/*** Date 转字串(本地时区)** @param date           日期* @param destDateFormat 输出的字串格式* @return 本地时区的字串形式*/public static String date2Str(Date date, String destDateFormat) {return date2StrTz(date, destDateFormat, localTimeZone());}public static String date2StrUTC(Date date, String destDateFormat) {return date2StrTz(date, destDateFormat, TZ.UTC);}/*** Date 转字串(指定时区)** @param date           日期* @param destDateFormat 格式* @param destTimeZone   转成什么时区的字串* @return 指定时区的字串形式*/public static String date2StrTz(Date date, String destDateFormat, TimeZone destTimeZone) {SimpleDateFormat sdf = new SimpleDateFormat(destDateFormat);sdf.setTimeZone(destTimeZone);return sdf.format(date);}/*** Date 转时间戳** @param date 日期时间* @return 时间戳*/public static long date2long(Date date) {return date.getTime();}/*** 字串(本地时区)转 Date** <pre>* 注意:该方法把传入的日期字串当成是本地时区来进行转换的。** 比如同样是 2017-04-02 15:33:08,在不同时区,* 返回的Date里的时间戳的值是不一样的!!即 date.getTime() 得到不一样的值** 北京时区(东八区)*      Sun Apr 02 15:33:08 CST 2017*      1491118388000* 东京时区(东九区)*      Sun Apr 02 15:33:08 JST 2017*      1491114788000* </pre>** @param localDateStr        待转换的字串* @param formatOfThisDateStr 字串的格式* @return 返回 "把该字串认为是本地时区的 java.util.Date"*/public static Date str2Date(String localDateStr, String formatOfThisDateStr) {return str2DateTz(localDateStr, formatOfThisDateStr, localTimeZone());}public static Date str2DateUTC(String utcDateStr, String formatOfThisDateStr) {return str2DateTz(utcDateStr, formatOfThisDateStr, localTimeZone());}/*** 字串(本地时区)转 Date** @param dateStr               待转换的字串* @param formatOfThisDateStr   字串的格式* @param timeZoneOfThisDateStr 字串的时区* @return 返回 "把该字串认为是本地时区的 java.util.Date"*/public static Date str2DateTz(String dateStr, String formatOfThisDateStr, TimeZone timeZoneOfThisDateStr) {try {SimpleDateFormat sdf = new SimpleDateFormat(formatOfThisDateStr);sdf.setTimeZone(timeZoneOfThisDateStr);return sdf.parse(dateStr);} catch (ParseException e) {throw new IllegalArgumentException(e);}}/*** 字串(本地时区)转时间戳** @param dateStr             待转换的字串* @param formatOfThisDateStr 字串的时区* @return 返回 "把该字串认为是本地时区的时间戳"*/public static long str2long(String dateStr, String formatOfThisDateStr) {return str2longTz(dateStr, formatOfThisDateStr, localTimeZone());}public static long str2longUTC(String dateStr, String formatOfThisDateStr) {return str2longTz(dateStr, formatOfThisDateStr, TZ.UTC);}/*** 字串(指定时区)转时间戳** @param dateStr               待转换的字串* @param formatOfThisDateStr   字串的时区* @param timeZoneOfThisDateStr* @return 返回 "把该字串认为是指定时区的时间戳"*/public static long str2longTz(String dateStr, String formatOfThisDateStr, TimeZone timeZoneOfThisDateStr) {return date2long(str2DateTz(dateStr, formatOfThisDateStr, timeZoneOfThisDateStr));}/*** 传入时间字串,指定格式和时区,转换成指定的时区的时间字串** @param srcDateString  源字串* @param srcDateFormat  源字串的格式* @param srcTimeZone    源字串的时区* @param destDateFormat 目的字串的格式* @param destTimeZone   目的字串的时区* @return 返回指定时区、指定格式的字串*/public static String str2str(String srcDateString,String srcDateFormat,TimeZone srcTimeZone,String destDateFormat,TimeZone destTimeZone) {SimpleDateFormat srcSdf = new SimpleDateFormat(srcDateFormat);srcSdf.setTimeZone(srcTimeZone);SimpleDateFormat destSdf = new SimpleDateFormat(destDateFormat);destSdf.setTimeZone(destTimeZone);Date sourceDate;try {sourceDate = srcSdf.parse(srcDateString);return destSdf.format(sourceDate);} catch (ParseException e) {throw new RuntimeException("Can not parse date", e);}}/************************************ 时间类型互转,字串,Date,long END ************************************//************************************ 获取时间 BEGIN ************************************//*** 获取本地日期时间* <p>* 这个 Date 其实是没有时区概念的,其里面存放的值是 System.currentTimeMillis() 的值* 但是 toString() 方法会根据系统时区来转成相应的字串* </p>** @return 返回 java.util.Date*/public static Date now() {return new Date();}/*** 获取 java.util.Date** @return 获取日期部分(去掉了时分秒和毫秒)*/public static Date nowDate() {return datePart(now());}/*** 获取时间戳(到达毫秒,13位数字)** @return 实际能不能精度达到毫秒,要看操作系统,详细参考 System.currentTimeMillis() 内的 javadoc*/private long currentTimeMillis() {return System.currentTimeMillis();}/*** 获取时间戳,精确到秒(也叫Unix时间戳,10位数字)** @return 返回Unix时间戳(仅到达秒)*/private long currentTimeSecs() {return System.currentTimeMillis() / 1000L;}/*** 获取日期部分** @param date 日期时间* @return 返回只要日期部分的Date(注意 : 重新new了一个Date , 入参得到Date不变化)*/public static Date datePart(Date date) {Calendar cal = Calendar.getInstance();cal.setTime(date);cal.set(Calendar.HOUR_OF_DAY, 0);cal.set(Calendar.MINUTE, 0);cal.set(Calendar.SECOND, 0);// 必须设置这个,否则毫秒数不同会导致compareDate方法在毫秒数上有差异cal.set(Calendar.MILLISECOND, 0);return cal.getTime();}/************************************ 获取时间 END ************************************//************************************ 时间顺序 BEGIN ************************************//*** 获得日期是星期几** @param date 日期时间* @return 返回1~7分别代表周一到周日*/public static int getDayOfWeek(Date date) {Calendar cal = Calendar.getInstance();cal.setTime(date);int index = cal.get(Calendar.DAY_OF_WEEK);switch (index) {case 1:return 7;case 2:return 1;case 3:return 2;case 4:return 3;case 5:return 4;case 6:return 5;default:return 6;}}/*** 获得日期是当月第几天,从1开始** @param date 日期时间* @return 返回第几天, 从1开始*/public static int getDayOfMonth(Date date) {Calendar cal = Calendar.getInstance();cal.setTime(date);int index = cal.get(Calendar.DAY_OF_MONTH);return index;}/*** 获得某个日期所在月份一共有多少天** @param date 日期时间* @return 日期所在月份有多少天*/public static int getHowManyDaysInMonth(Date date) {Calendar cal = Calendar.getInstance();cal.setTime(date);return cal.getActualMaximum(Calendar.DATE);}/*** 获得指定日期所在当月第一天(时间部分会保留)** @param date 日期时间* @return 日期所在月份的开始那天*/public static Date getStartDayOfMonth(Date date) {Calendar cal = Calendar.getInstance();cal.setTime(date);cal.set(Calendar.DATE, 1);return cal.getTime();}/*** 获得指定日期所在当月最后一天(时间部分会保留), 能正确识别月份不同天数** @param date 日期时间* @return 日期所在月份最后一天*/public static Date getLastDayOfMonth(Date date) {Calendar cal = Calendar.getInstance();cal.setTime(date);cal.set(Calendar.DATE, 1);cal.add(Calendar.MONTH, 1);cal.add(Calendar.DATE, -1);return cal.getTime();}/************************************ 时间顺序 END ************************************//************************************ 时间比较 BEGIN ************************************//*** 判断两个日期时间是否相等,连秒、毫秒都必须相等** @param date1 日期时间1* @param date2 日期时间2* @return true则相等,反之不等*/public static boolean isEqualDateTime(Date date1, Date date2) {return date1.getTime() == date2.getTime();}/*** 仅仅比较日期部分是否相等, 不比较时间部分<br>* 相等: 2015-08-19 14:28:47 和 2015-08-19 14:28:51、2015-08-18 和 2015-08-18<br>* 不等: 2015-08-18 和 2015-08-19、2015-08-19 14:32:51和2015-08-18 14:32:57** @param date1 日期1* @param date2 日期2* @return true则相等,反之不等*/public static boolean isEqualDate(Date date1, Date date2) {date1 = datePart(date1);date2 = datePart(date2);return isEqualDateTime(date1, date2);}/*** 比较日期时间先后顺序 <br>* 辅助理解: 1.所谓时间大于,未来的时间比现在大* 2.看着入参列出等式,如date1-date2,结果是1就表示大于0,即date1-date2>0亦即date1>date2** @param date1* @param date2* @return date1>date2返回1,date1<date2返回-1,date1=date2返回0 <br>*/public static int compareDateTime(Date date1, Date date2) {Calendar cal1 = Calendar.getInstance();cal1.setTime(date1);Calendar cal2 = Calendar.getInstance();cal2.setTime(date2);if (isEqualDateTime(date1, date2)) {return 0;}if (cal1.after(cal2)) {return 1;} else {return -1;}}/*** 比较日期的先后顺序<br>** @param date1* @param date2* @return date1>date2返回1,date1<date2返回-1,date1=date2返回0 <br>*/public static int compareDate(Date date1, Date date2) {date1 = datePart(date1);date2 = datePart(date2);return compareDateTime(date1, date2);}/************************************ 时间比较 END ************************************//************************************ 时间加减 BEGIN ************************************//*** 增加或减少年份数,注意入参本身是不改变的** @param date   日期* @param amount 可以传负整数* @return 计算结果的新值, 入参本身不变!*/public static Date addYears(Date date, int amount) {Calendar cal = Calendar.getInstance();cal.setTime(date);cal.add(Calendar.YEAR, amount);return cal.getTime();}/*** 增加或减少月份数,注意入参本身是不改变的** @param date   日期* @param amount 可以传负整数* @return 计算结果的新值, 入参本身不变!*/public static Date addMonths(Date date, int amount) {Calendar cal = Calendar.getInstance();cal.setTime(date);cal.add(Calendar.MONTH, amount);return cal.getTime();}/*** 增加或减少天数,注意入参本身是不改变的** @param date   日期* @param amount 可以传负整数* @return 计算结果的新值, 入参本身不变!*/public static Date addDays(Date date, int amount) {Calendar cal = Calendar.getInstance();cal.setTime(date);cal.add(Calendar.DATE, amount);return cal.getTime();}/*** 增加或减少小时数,注意入参本身是不改变的** @param date* @param amount 可以传负整数* @return 计算结果的新值, 入参本身不变!*/public static Date addHours(Date date, int amount) {Calendar cal = Calendar.getInstance();cal.setTime(date);cal.add(Calendar.HOUR_OF_DAY, amount);// 用HOUR和HOUR_OF_DAY结果一样return cal.getTime();}/*** 增加或减少分钟数,注意入参本身是不改变的** @param date* @param amount 可以传负整数* @return 计算结果的新值, 入参本身不变!*/public static Date addMinutes(Date date, int amount) {Calendar cal = Calendar.getInstance();cal.setTime(date);cal.add(Calendar.MINUTE, amount);return cal.getTime();}/*** 增加或减少秒数,注意入参本身是不改变的** @param date* @param amount 可以传负整数* @return 计算结果的新值, 入参本身不变!*/public static Date addSeconds(Date date, int amount) {Calendar cal = Calendar.getInstance();cal.setTime(date);cal.add(Calendar.SECOND, amount);return cal.getTime();}/************************************ 时间加减 END ************************************//************************************ 时间间隔,其他 BEGIN ************************************//*** 1. 计算两个日期之间有多少天(取了绝对值)<br>* 2. 只考虑日期,不考虑时间 <br>* 3. 包括开始日期,不包括结束 <br>* 4. 结果不会是负数 <br>* 5. 举例: 2015-08-19 和 2015-08-18 结果是1 2015-08-19和2015-08-19结果是0 <br>** @param endDate   第一个时间* @param beginDate 第二个时间* @return 天数, 正数!*/public static long getTwoDateInterval(Date endDate, Date beginDate) {endDate = datePart(endDate);beginDate = datePart(beginDate);return Math.abs((endDate.getTime() - beginDate.getTime()) / (24 * 60 * 60 * 1000L));}/*** 查询两个时间之间相差的天数,不足一天按一天计算<br>* 两个日期可以随便传按照任意顺序传入** @param endDateTime   具体到时间,如2015-11-17 12:29:52* @param beginDateTime 具体到时间,如2015-11-17 12:29:52* @return*/public static long getTwoDateTimeInterval(Date endDateTime, Date beginDateTime) {double d = ((double) (endDateTime.getTime() - beginDateTime.getTime())) / ((double) 24 * 60 * 60 * 1000L);d = Math.abs(d);Double day = Math.ceil(d);return Math.abs(day.longValue());}/*** 1. 计算两个日期之间有多少天<br>* 2. 只考虑日期,不考虑时间 <br>* 3. 既包括开始日期,也包括结束 <br>* 4. 举例: 2015-08-19 和 2015-08-18 结果是2 2015-08-19和2015-08-19结果是1 <br>** @param endDate* @param beginDate* @return*/public static long getTwoDateIntervalContainEnd(Date endDate, Date beginDate) {return getTwoDateInterval(endDate, beginDate) + 1;}/*** 获得传入的日期时间,距离当天 24:00:00 的分钟数* <pre>*     注意: 某天的 24:00:00 就是下一天的 00:00:00, 例如 2015-04-04 24:00:00,其实是 2015-04-05 00:00:00* </pre>** @param date 日期时间* @return 返回分钟数, 不足一分钟算0分钟, 例如 2015-04-04 23:59:01,距离今天结束还有59秒,接口返回0. 计算的结果只和时间的部分有关,和日期部分无关*/public static int howManyMinutesTillDayEnd(Date date) {Calendar cal = Calendar.getInstance();cal.setTime(date);cal.set(Calendar.HOUR_OF_DAY, 24);cal.set(Calendar.MINUTE, 0);cal.set(Calendar.SECOND, 0);cal.set(Calendar.MILLISECOND, 0);Date day24 = cal.getTime();return (int) ((day24.getTime() - date.getTime()) / (1000 * 60L));}/*** 获得传入的日期时间,距离当天 24:00:00 的秒数** @param date 日期时间* @return 返回秒数. 计算的结果只和时间的部分有关,和日期部分无关*/public static int howManySecondsTillDayEnd(Date date) {Calendar cal = Calendar.getInstance();cal.setTime(date);cal.set(Calendar.HOUR_OF_DAY, 24);cal.set(Calendar.MINUTE, 0);cal.set(Calendar.SECOND, 0);cal.set(Calendar.MILLISECOND, 0);Date day24 = cal.getTime();return (int) ((day24.getTime() - date.getTime()) / 1000L);}/************************************ 时间间隔,其他 END ************************************/
}

DateUtil,时区,常用的日期接口相关推荐

  1. 一些常用的IHTMLXX接口

    最近经常用到IHTMLxx接口,所以把一些常用的都收集起来,免得每次都查MSDN,麻烦. IHTMLDocument2.IHTMLElement.IHTMLElementCollection.ITHM ...

  2. python使用_获取常用特定日期(如去年/季度/当月/上月/本周/首日等)

    通过datetime和dateutil进行常用日期的获取: 如: 今年,去年,明年 当前季度 本月,上月,去年同期,今年一月 今天,昨天,明天, 本周.本月.本季度.本年第一天, 本周.本月.本季度. ...

  3. java中常用的日期工具类

    java中常用的日期工具类 日期相关的类: package net.yto.ofclacct.core.util;import java.text.ParseException; import jav ...

  4. 【Python金融量化 1- 100 】了解Python及常用财经数据接口包

    了解Python及常用财经数据接口包 背景介绍: Python是一种计算机程序设计语言,它诞生于20世纪90年代初,正在逐渐被广泛运用中. Python的创始人是Guido van Rossum.相传 ...

  5. jsp中两个字符串格式的日期可以相减吗_举个栗子!Tableau 技巧(126):学几个常用的日期函数...

    当我们的数据源有日期字段时,想根据日期实现需要的分析呈现,使用函数对日期进行计算,就非常有必要了! Tableau 中的日期函数很多,今天我们分享数据粉常用的 7 个函数,看它们如何帮助实现日期的计算 ...

  6. 常用的函数式接口_Supplier接口

    常用函数式接口 JDK提供了大量常用的函数式接口以丰富Lambda的典型使用场景,它们主要在java.util.function 包中被提供. 下面是最简单的几个接口及使用示例. Supplier接口 ...

  7. SQLServer常用的日期和时间函数梳理

    今天给大家分享一下SQLServer常用的日期和时间函数知识笔记,希望对大家能有所帮助! 1.DATEADD(datepart,number,date) 作用:返回给指定日期加一个时间间隔后新的dat ...

  8. SpringMVC常用的视图接口分类及实现类

    SpringMVC中常用的视图接口分类及对应的实现类: URL资源视图:InternalResourceView.JstlView 文档视图:AbstractExcelView.AbstractPdf ...

  9. MySql日期处理系列-常用的日期推算处理

    以下都是我平时用的一些日期推算处理方法,方法并不一定是最有效率的.全部均通过测试! 转载请注明来自[phpchina.com] #title: 常用的日期推算处理 #auther: 小强(占卜师) # ...

最新文章

  1. overflow:hidden;zoom:1 理解转__
  2. java 中文怎么截取,java String 中文 字符串 截取
  3. Factory Method模式的误区:Factory Method模式是简化版的Abstract Factory吗?
  4. 关于 Linux 的配置文件 /etc/profile 路径出错后相关的命令失效解决方式(如:ls,vi不能用)...
  5. Oracle集群(RAC)及 jdbc 连接双机数据库
  6. sstream用法(后续更新)
  7. 凤凰系统(Phoenix OS)PC版安装,电脑上体验功能丰富的安卓系统
  8. 儿童早教APP开发成品案例
  9. 微软2008年7月「最有价值专家」(MVP)当选名单
  10. 计算机重装后如何连接无线网络,笔记本重装系统后无法连接无线网络怎么办
  11. Python3.8场景式编程学习与训练- 第1章 入门基础 Python学习方法论与学习资源
  12. 无法更新运行时文件夹共享状态_关于iPadOS 13.4更新的5件事
  13. 新电脑 安装idea迁移设置和插件注意事项
  14. 互联网行业职位介绍 —— OD、PM、RD、FE、UE、QA、OP、DBA...
  15. BAT面试经验分享(机器学习算法岗)
  16. 批量选择图片_PS的批量处理功能
  17. TopCoder入门教程(转载)
  18. 分享一个600块钱的Python私活单,金融Excel数据清洗
  19. 大连的房价很便宜了!
  20. ngrok 把内网URL转换成外网URL

热门文章

  1. Linux-定时任务调度
  2. linux查看磁盘信息
  3. 充电宝良莠不齐 购买使用需谨慎
  4. jQuery练习:使用jQuery获取表单数据,使用弹窗显示。
  5. Android的专用驱动
  6. 破解10亿数据点数据实时可视化
  7. git管理工具SourceTree --- 提交,拉取,推送
  8. faiss python安装_faiss部署初体验
  9. 搜索引擎原理、技术与系统读书笔记(4)
  10. 游戏设计自学记录(24)