Java 中的日期与时间
Java 日期时间
标签 : Java基础
Date
java.util.Date
对象表示一个精确到毫秒的瞬间; 但由于Date
从JDK1.0起就开始存在了,历史悠久,而且功能强大(既包含日期,也包含时间),所以他的大部分构造器/方法都已Deprecated,因此就不再推荐使用(如果贸然使用的话,可能会出现性能/安全方面的问题);下面我仅介绍它还剩下的为数不多的几个方法(这些方法的共同点是Date
与毫秒值的转换):
构造器
Date()
: 在底层调用System.currentTimeMillis()
作为日期参数.Date(long date)
: 根据指定的long整数(从1970-1-1 00:00:00以来经过的毫秒数)来生成Date对象.
方法
boolean after(Date when)
: 测试this日期是否在指定日期when之后;boolean before(Date when)
: 测试this日期是否在指定日期when之前;long getTime()
: 获取从1979-01-01 00:00:00 到Date对象之间经过的毫秒值;void setTime(long time)
: 设置时间,time含义上同.
/*** Created by jifang on 15/12/30.*/
public class DateTest {@Testpublic void test() {Date dateBefore = new Date();Date dateAfter = new Date(System.currentTimeMillis() + 1);System.out.println("before: " + dateBefore.getTime());System.out.println("after: " + dateAfter.getTime());System.out.println(dateBefore.before(dateAfter));System.out.println(dateAfter.after(dateBefore));dateBefore.setTime(System.currentTimeMillis());System.out.println(dateBefore.getTime());System.out.println(dateBefore.before(dateAfter));}
}
Calendar
由于Date
存在缺陷,所以JDK又提供了java.util.Calendar
来处理日期和时间.Calendar
是一个抽象类,是所有日历类的模板,因此,我们可以继承Calendar来实现其他的历法(比如阴历);
Java中提供了一种Calendar的默认实现java.util.GregorianCalendar
格里高利日历(其实JDK还默认提供了一款日本历法java.util.JapaneseImperialCalendar
),也就是我们所说的公历. 使用Calendar.getInstance();
获取的就是默认的GregorianCalendar
,getInstance()
方法的内部会调用cal = new GregorianCalendar(zone, aLocale);
来生成一个格里高利日历实例.
- Calendar还可以和Date自由转换.
public class CalendarTest {@Testpublic void test() {Calendar calendar = Calendar.getInstance();Date date = calendar.getTime();Calendar newCalendar = Calendar.getInstance();newCalendar.setTime(date);System.out.println(calendar.get(Calendar.DATE));}
}
- Calendar类提供了大量访问/修改日期/时间的方法, 常用的方法如下:
Method | Description |
---|---|
void add(int field, int amount)
|
Adds or subtracts the specified amount of time to the given calendar field, based on the calendar’s rules. |
int get(int field)
|
Returns the value of the given calendar field. |
int getActualMaximum(int field)
|
Returns the maximum value that the specified calendar field could have, given the time value of this Calendar. |
int getActualMinimum(int field)
|
Returns the minimum value that the specified calendar field could have, given the time value of this Calendar. |
void roll(int field, int amount)
|
Adds the specified (signed) amount to the specified calendar field without changing larger fields. |
void set(int field, int value)
|
Sets the given calendar field to the given value. |
void set(int year, int month, int date)
|
Sets the values for the calendar fields YEAR, MONTH, and DAY_OF_MONTH. |
void set(int year, int month, int date, int hourOfDay, int minute, int second)
|
Sets the values for the fields YEAR, MONTH, DAY_OF_MONTH, HOUR, MINUTE, and SECOND. |
void setTimeInMillis(long millis)
|
Sets this Calendar’s current time from the given long value. |
long getTimeInMillis()
|
Returns this Calendar’s time value in milliseconds. |
上面的很多方法都需要一个int类型的field参数, field是Calendar类的类变量, 如:Calendar.DATE
Calendar.MONTH
Calendar.HOUR
Calendar.DAY_OF_WEEK
, 但需要指出的是Calendar.MONTH
月份的起始值不是1, 而是0(一月:0, 二月:1 …), Calendar.DAY_OF_WEEK
代表的星期, 起始值是周日(周日:1, 周一:2 …)(其他细节请参考JDK文档).
注意:
- 如果
Calendar
没有设置相关的值, 就以当前系统时间来设置. add(int field, int amount)
的功能非常强大, 如果需要增加某字段, 则让amount为正数, 如果要减少某字段的值, 让amount为负数. 且当超出他的允许范围时, 会发生进位.roll()
的含义与用法和add()
的类似,但是当被修改的字段超出它允许的范围时, 他不会进位.set(int field, int value)
方法具有延迟修改的功能:他内部设置了一个成员变量,以指示日历字段field已经被修改,但是该Calendar所代表的时间不会立即修改, 他会直到下次调用get/getTime/getTimeInMillis/add/roll时才会重新计算日历时间.
public int get(int field)
{complete();return internalGet(field);
}
public long getTimeInMillis() {if (!isTimeSet) {updateTime();}return time;
}
- 测试
public class CalendarTest {@Testpublic void test() {Calendar calendar = Calendar.getInstance();calendar.set(2011, Calendar.JULY, 31);calendar.set(Calendar.MONTH, Calendar.SEPTEMBER);// 将下面注释放开, 再测试// System.out.println(calendar.get(Calendar.MONTH) + 1 + "月" + calendar.get(Calendar.DATE) + "日");calendar.set(Calendar.DATE, 5);System.out.println(calendar.get(Calendar.MONTH) + 1 + "月" + calendar.get(Calendar.DATE) + "日");}
}
日期格式化
完成字符串与日期对象的转化(format/parse)
DateFormat
java.text.DateFormat
是一个抽象类, 他提供了如下几个方法获取DateFormat对象.
方法 | 描述 |
---|---|
static DateFormat getDateInstance()
|
Gets the date formatter with the default formatting style for the default locale. |
static DateFormat getDateTimeInstance()
|
Gets the date/time formatter with the default formatting style for the default locale. |
static DateFormat getTimeInstance()
|
Gets the time formatter with the default formatting style for the default locale. |
其实上面三个方法还可以指定日期/时间的样式, 如FULL/LONG/MEDIUM/SHOT
, 通过这四个样式参数可以控制生成的格式化字符串. 但由于在我们的实际开发中很少直接用DateFormat
类,因此就不对其做过多的介绍.而我们比较常用的是其子类SimpleDateFormat
(其实上面几个getXxxInstance方法返回的也是SimpleDateFormat实例)
DateFormat dateFormat = DateFormat.getTimeInstance();
System.out.println(dateFormat.getClass().getName());
SimpleDateFormat
java.text.SimpleDateFormat
可以非常灵活的格式化Date, 也可以用于解析各种格式的日期字符串.创建SimpleDateFormat
对象时需要传入一个pattern字符串,这个pattern不是正则表达式,而是一个日期模板字符串.
/*** Created by jifang on 15/12/30.*/
public class FormatTest {@Testpublic void client() throws ParseException {DateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");// Date -> StringDate date = new Date(System.currentTimeMillis());System.out.println(format.format(date));// String -> DateString timeString = "2015-12-30 08:53:21";Date newDate = format.parse(timeString);System.out.println(newDate);}
}
在时间日期格式化时, 有下面几个方法是最常用的:
方法 | 描述 | 小结 |
---|---|---|
String format(Date date)
|
Formats a Date into a date/time string. | Date -> String |
Date parse(String source)
|
Parses text from the beginning of the given string to produce a date. | String -> Date |
当然, pattern我们还可以根据我们的需求有其他的定制形式:
@Testpublic void client() throws ParseException {DateFormat format = new SimpleDateFormat("yy年MM月dd日 hh时mm分ss秒");// Date -> StringDate date = new Date(System.currentTimeMillis());System.out.println(format.format(date));// String -> DateString timeString = "15年12月30日 09时00分29秒";Date newDate = format.parse(timeString);System.out.println(newDate);}
可以看出SimpleDateFormat
把日期格式化成怎样的字符串以及能把怎样的字符串解析成Date, 完全取决于创建对象时指定的pattern参数,其他的pattern参数以及SimpleDateFormat
的方法可以参考JDK文档.
实战
时间存储
将时间存入DB会涉及到跨时区的问题(同一个UTC时间在各个时区显示不同的数值).因此,在设计数据库表结构时需要小心谨慎,不能简单使用数据库提供的TIMESTAMP
或DATETIME
(详见:廖雪峰博客-如何正确地处理时间),比较推荐的是选用一个整数类型(如BIGINT
64位)来存储从1970-01-01 00:00:00
到当前时间所经过毫秒数的一个绝对数值.
- 优点:
读取的时间(Long整数)只需要按照用户所在的时区格式化为字符串就能正确地显示出来. - 缺点
当开发人员、DBA直接查看DB时,只能看到一串数字.
线程安全formatter
时间的格式化和解析格式在一个项目中往往只用一种,因此没有必要每次使用时都new
出一个Formatter
来. 但SimpleDateFormat
的format()
与parse()
并非线程安全(详见: 关于SimpleDateFormat的非线程安全问题及其解决方案), 因此在并发环境中要注意同步或使用ThreadLocal
控制:
- DateUtil
public class DateUtils {// Each thread will have its own copy of the SimpleDateFormatprivate static final ThreadLocal<SimpleDateFormat> formatterMap = new ThreadLocal<SimpleDateFormat>() {protected SimpleDateFormat initialValue() {return new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");}};public static String format(Object obj) {return formatterMap.get().format(obj);}public static Date parse(String source) throws ParseException {return formatterMap.get().parse(source);}public static void main(String[] args) {long start = System.currentTimeMillis();final String[] data = {"1999-11-01 11:11:11","2001-07-08 06:06:06","2007-01-31 02:28:31","1999-11-01 11:11:11","2001-07-08 06:06:06","2007-01-31 02:28:31"};List<Thread> threads = new ArrayList<>(data.length);for (int i = 0; i < data.length; ++i) {final int i2 = i;Thread thread = new Thread(new Runnable() {@Overridepublic void run() {try {for (int j = 0; j < 10_000; j++) {String from = data[i2];Date d = parse(from);String to = format(d);System.out.println("i: " + i2 + "\tj: " + j + "\tThreadID: "+ Thread.currentThread().getId() + "\tThreadName: "+ Thread.currentThread().getName() + "\t" + from + "\t" + to);if (!from.equals(to)) {throw new RuntimeException("date conversion failed after " + j+ " iterations. Expected " + from + " but got " + to);}}} catch (ParseException e) {throw new RuntimeException("parse failed");}}}, "formatter_test_thread_" + i);threads.add(thread);thread.start();}for (Thread thread : threads) {try {thread.join();} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("total consume [" + (System.currentTimeMillis() - start) + "] ms.");}
}
Java 中的日期与时间相关推荐
- Java中获取日期和时间
Java中获取日期和时间 1.创建 java.util.Calendar 实例,调用其 get()方法传入不同的参数即可获 得参数所对应的值 import java.util.Calender; // ...
- 关于Java中的日期与时间的相关类说明详解
文章目录 1.关于Java元年与时间戳 2.关于Date类 2.1常用API代码展示 3.关于Calendar类 3.1获取Calendar对象 3.2创建自定义的Calendar对象 3.2Cale ...
- 详解java中的日期与时间;新旧API对比;各种日期格式转换
一.基本概念 1.本地时间 不同的时区,在同一时刻,本地时间是不同的. 全球一共分为24个时区,伦敦所在的时区称为标准时区,其他时区按东/西偏移的小时区分,北京所在的时区是东八区. 2.时区 GMT ...
- Java中的日期和时间的API(Calendar)
java.util.Calendar类是一个抽象类,主要用于完成日期字段之间相互操作的功能 ①实例化 方式一:创建其子类(GregorianCalendar)的对象 方式二:调用其静态方法getI ...
- JAVA中关于日期和时间的计算(万年历)
最近参加算法类的比赛,第一题常考关于日期在万年历中计算的问题,其实JDK提供的原生API中就有相关的计算方法,在Calendar类中就封装有相关的API,具体计算方法如下: import java.t ...
- java中封装日期加时间_java日期处理简单封装
1 packageluojing.date;2 3 importjava.io.Serializable;4 importjava.text.ParseException;5 importjava.t ...
- java时间选择,JAVA中的日期和时间选择器
I am looking for date and time picker, but found just JCalender that's for date picker and does not ...
- Java中有关日期的操作,昨天晚上赴约,搞到12点多才回来,今天写这一小段代码都花了一段漫长的时间,哎。。...
Java中有关日期的操作,昨天晚上赴约,搞到12点多才回来,今天写这一小段代码都花了一段漫长的时间,哎.. 代码奉上: /** * * @param date * @return which mont ...
- java 正则表达式 判断 日期_怎么在java中利用正则表达式对时间日期进行判断
怎么在java中利用正则表达式对时间日期进行判断 发布时间:2020-12-08 16:18:34 来源:亿速云 阅读:105 作者:Leah 这篇文章给大家介绍怎么在java中利用正则表达式对时间日 ...
最新文章
- [NC15034]德玛西亚万岁
- 浅析 Linux 初始化 init 系统:sysvinit
- 递归式的时间复杂度的计算
- 常说SCI论文有多少篇,那你知道SCI是什么吗?
- 用几条shell命令快速去重10G数据
- linux之ubunt把启动栏底部和左边切换
- 【渝粤题库】陕西师范大学800011 专题地图制图
- JAVA连接数据库ij_Derby 客户端 ij使用
- 220v转5v阻容降压电路
- js实现放大镜的效果
- 对通用查询组件初始化组织过滤条件
- 普中开发板白屏_普中开发板送的12864为什么程序写进去,屏幕不显示?
- win10不能安装破解软件:提示系统资源不足,无法完成请求服务的解决方法
- 下载正版Origin Pro 2022 教程 及 如何 激 活
- MySQL的一级索引和二级索引介绍
- JDBC百宝箱方法集合(增删改等)
- 电阻电路的等效变化(Ⅰ)
- 两代 Windows 性能大比拼!Win8 完胜 Win7
- html5 任务列表,《怪物猎人 世界:冰原》每周活动任务列表(不断更新中)
- 文博界最早利用计算机技术的,现代计算机技术博物馆中的应用
热门文章
- (软件工程复习核心重点)第九章面向对象分析-第三节:面向对象分析之建立动态模型和功能模型
- (数据库系统概论|王珊)第三章关系数据库标准语言SQL-第二、三节:数据定义
- 使用 dpu 检视 dump 中的字符串.
- Thrift 异步模式
- [Python]网络爬虫(七):Python中的正则表达式教程
- 套接字I/O模型-重叠I/O
- 1304. 和为零的N个唯一整数
- HDOJ 1757 A Simple Math Problem(矩阵快速幂)
- python2 http请求post、get
- etcd和redis的比较和日常使用场景