Date
一、简介:
时间与日期API,表示特定的瞬间,精确到毫秒。
可变类,线程不安全,可以通过setXXX()对Year、Month、Day、Minute、Sec进行修改。
Date 月份从0开始,一月是0,十二月是11。
二、API:
初始化:
public void test1(){
Date date = new Date(); //当前时间的Date对象
Date date1 = new Date(200000L); //从1970, 00:00:00 GMT开始毫秒数为参数创建的Date对象
@Deprecated
Date date2 = new Date(2021, 9, 22); //Sat Oct 22 00:00:00 CST 3921 OCT为10月
Date date3 = new Date(2021, 9, 22, 18, 06, 34); //Sat Oct 22 18:06:34 CST 3921
//get、set方法
System.out.println(date2.getMonth()); //9,内部进行了-1
date2.setMonth(10);
System.out.println(date2.getMonth()); //10,内部进行了-1
}
方法:
-
long getTime():返回从1970.1.1.00.00.00所流逝的Date对象所代表的毫秒数。
-
boolean before(Date when):测试此日期是否在指定日期之前。
-
boolean after(Date when):测试此日期是否在指定日期之前。
-
Instant toInstant():返回一个时间戳。
-
setTime(long time):修改流逝时间。
SimpleDateFormat
一、简介:
不与语言环境有关的方式来格式化和解析日期的具体类,线程不安全。
作用:
通常用来进行日期 与 字符串文本的转换:
-
格式化:日期 -> 文本
-
解析:文本 -> 日期
二、格式化(时间 -> 文本):
Pattern格式:
Letter | Date or Time Component | Presentation | Examples |
---|---|---|---|
G | Era designator | Text | AD |
y | Year | Year | 1996 ; 96 |
Y | Week year | Year | 2009 ; 09 |
M | Month in year | Month | July ; Jul ; 07 |
w | Week in year | Number | 27 |
W | Week in month | Number | 2 |
D | Day in year | Number | 189 |
d | Day in month | Number | 10 |
F | Day of week in month | Number | 2 |
E | Day name in week | Text | Tuesday ; Tue |
u | Day number of week (1 = Monday, …, 7 = Sunday) | Number | 1 |
a | Am/pm marker | Text | PM |
H | Hour in day (0-23) | Number | 0 |
k | Hour in day (1-24) | Number | 24 |
K | Hour in am/pm (0-11) | Number | 0 |
h | Hour in am/pm (1-12) | Number | 12 |
m | Minute in hour | Number | 30 |
s | Second in minute | Number | 55 |
S | Millisecond | Number | 978 |
z | Time zone | General time zone | Pacific Standard Time ; PST ; GMT-08:00 |
Z | Time zone | RFC 822 time zone | -0800 |
X | Time zone | ISO 8601 time zone | -08 ; -0800 ; -08:00 |
简单样例:
Date and Time Pattern | Result |
---|---|
"yyyy.MM.dd G 'at' HH:mm:ss z" | 2001.07.04 AD at 12:08:56 PDT |
"EEE, MMM d, ''yy" | Wed, Jul 4, '01 |
"h:mm a" | 12:08 PM |
"hh 'o''clock' a, zzzz" | 12 o'clock PM, Pacific Daylight Time |
"K:mm a, z" | 0:08 PM, PDT |
"yyyyy.MMMMM.dd GGG hh:mm aaa" | 02001.July.04 AD 12:08 PM |
"EEE, d MMM yyyy HH:mm:ss Z" | Wed, 4 Jul 2001 12:08:56 -0700 |
"yyMMddHHmmssZ" | 010704120856-0700 |
"yyyy-MM-dd'T'HH:mm:ss.SSSZ" | 2001-07-04T12:08:56.235-0700 |
"yyyy-MM-dd'T'HH:mm:ss.SSSXXX" | 2001-07-04T12:08:56.235-07:00 |
"YYYY-'W'ww-u" | 2001-W27-3 |
步骤:
-
以Pattern格式的字符串为参数创建一个SimpleDateFormat对象。
-
调用format方法,传入一个Date对象进行格式化。
示例代码:
/*Date格式化*/
public void test1(){
SimpleDateFormat simpleDateFormat = new SimpleDateFormat();
String format = simpleDateFormat.format(new Date());
System.out.println(format);//21-9-22 下午6:58
SimpleDateFormat simpleDateFormat1 = new SimpleDateFormat("yyyy年-MM月-dd日-HH点-mm分-ss秒");
String format1 = simpleDateFormat1.format(new Date());
System.out.println(format1);//2021年-09月-22日-18点-58分-04秒
}
yyyy与YYYY区别:
问题:由于每一年的最后一周可能会出现一周跨两个年度的情况,例如2017年12月31日,本周(2017年12月31日-2018年1月6日),由于YYYY表示当天所在的周属于的年份,属于下一年,则最终该日期会表示为:2018-12-31
yyyy - Day year 表示当天属于的年份
YYYY - Week year 表示当天所在的周属于的年份
public static void main(String[] args) {
Calendar calendar = Calendar.getInstance();
calendar.set(2017, Calendar.DECEMBER, 31);
Date strDate1 = calendar.getTime();
SimpleDateFormat sf1 = new SimpleDateFormat("YYYY-MM-dd");
System.out.println("大写 YYYY: " + sf1.format(strDate1));// 大写 YYYY: 2018-12-31
SimpleDateFormat sf2 = new SimpleDateFormat("yyyy-MM-dd");
System.out.println("小写 yyyy: " + sf2.format(strDate1));// 小写 yyyy: 2017-12-31
}
三、解析:
步骤:
-
创建一个SimpleDateFormat(String pattern)对象,传入一个pattern指定格式。
-
调用parse(String source)方法,传入一个文本,将其转换为日期对象。
示例代码:
/*解析*/
public void test2(){
SimpleDateFormat simpleDateFormat1 =new SimpleDateFormat("yyyy年-MM月-DD日-HH点-mm分-ss秒");
try {
Date parse = simpleDateFormat1.parse("2020年-5月-7日-11点-31分-33秒");
} catch (ParseException e) {
e.printStackTrace();
}
}
四、保证线程安全
为什么线程不安全:
1、format格式化是由于calendar为线程共享资源,可能会存在多个线程同时进行修改的情况,从而出现线程安全问题。
private StringBuffer format(Date date, StringBuffer toAppendTo,
FieldDelegate delegate) {
// Convert input date to time field list
calendar.setTime(date);
boolean useDateFormatSymbols = useDateFormatSymbols();
for (int i = 0; i < compiledPattern.length; ) {
..
}
....
}
2、parse方法也是线程不安全的,parse方法实际调用的是CalenderBuilder的establish来进行解析,其方法中主要步骤不是原子操作
如何保证线程安全 ?
1、使用同步机制比如Sychorized关键字
2、使用线程封闭技术,即ThreadLocal类,为每个线程创建一个对象的副本。
3、使用局部变量
Calendar
一、简介
表示日历,Calendar是抽象基类,用于完成日期字段之间相互操作的功能。
二、API
初始化:
- 调用Calendar.getInstance()。
- 创建其子类的构造方法,GregorianCalendar gregorianCalendar = new GregorianCalendar()。
Calendar instance = Calendar.getInstance();
GregorianCalendar gregorianCalendar = new GregorianCalendar()
方法:
public void set(int field,int value)
public void add(int field,int amount)
public final Date getTime()
public final void setTime(Date date)
public void test1(){
Calendar instance = Calendar.getInstance(); //目前为9月22日、星期三
int i = instance.get(Calendar.MONTH);
//Calendar.MONTH为Calender对象的月份的所对应的filed数组的下标 = 2,fields[field]
//Calendar.MONTH常量值,如:public static final int MONTH = 2;
System.out.println(i); //8
System.out.println(Calendar.MONTH);//2
instance.set(Calendar.MONTH,10);
System.out.println("//");
i = instance.get(Calendar.MONTH);
System.out.println(i);//10
System.out.println(Calendar.MONTH);//2
------------------------------------------------------
int i1 = instance.get(Calendar.WEEK_OF_YEAR);
System.out.println(i1); //39
System.out.println(Calendar.WEEK_OF_YEAR);//2
}