Date類
Date類 實現Serializable Cloneable Comparable 接口
他的子類有:Date(sql包下的) Time Timestamp 這三個子類其實都是sql包下的
Date的構造方法:
Date() | 獲取當前的時間對象 | |
Date(long date) | 將時間戳數字轉化爲Date類對象 |
Date常用方法:
long getTime() | 將時間以long類型返回 |
boolean after(Date when) |
是否在指定時間之後 |
boolean before(Date when) | 是否在指定時間之前 |
Calendar日曆類 實現Serializable Cloneable Comparable 接口 ,是一個抽象類,構造方法都被protected修飾
用法比Date複雜,但是功能是日曆,而不再需要我們進行long類型的加減操
常用方法:
Calendar getInstance() | 獲取calendar的示例對象 |
int get(int field) | 獲取calendar的成員日期或其他時間數據 |
set(int field, int value) | 設置指定成員的數據內容 |
abstract void add(int field, int amount) | 在指定的成員數據上進行加法運算 |
public static void main(String[] args) {
Calendar instance = Calendar.getInstance();
instance.add(Calendar.MONTH, 6); //計算半年後的日期
instance.set(instance.get(Calendar.DAY_OF_MONTH), 3); // 設置這個月的第三天,即半年後的那個月的第三天
System.out.println(String.format("日曆爲,%s,%s,%s %s:%s:%s", instance.get(Calendar.YEAR)
, instance.get(Calendar.MONDAY)
, instance.get(Calendar.DAY_OF_MONTH)
, instance.get(Calendar.HOUR_OF_DAY)
, instance.get(Calendar.MINUTE)
, instance.get(Calendar.SECOND)
));
}
SimpleDateFormat:格式化日期類,在java.text 包下面,這個包是國際化都放在這個裏面
這個類繼承了DateFormat
format(Date date) | 將日期格式化轉化爲字符串 |
parse(String source) | 將字符串轉化爲日期 |
SimpleDateFormat(String pattern) | 創建對象,設置匹配模式 |
如果想成功的對日期進行格式化或者將字符串轉化爲日早起,那麼 就必須存在有一個日期的匹配表達式,而這組表達式裏面最重要的幾個日期單位年(yyyy) 月(MM)日(dd)時(HH)分(mm)秒(ss)毫秒(SSS)
public static void main(String[] args) throws Exception{
Date date = new Date();
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
System.out.println(dateFormat.format(date));
String str = "2020-04-01 22:23:11.606";
Date parse = dateFormat.parse(str);
System.out.println(parse);
}
java中常用的 數據類型和字符串相互轉換的常用方法
LocalDate類
在jdk1.8 之後的版本里,java追加了一個新的日期時間的處理包,java.time ,在這個包有三個類比較重要LocalDate
LocalTime ,LocalDateTime ,通用Calendar類相比更加簡單
public static void main(String[] args) throws Exception {
LocalDate localDate = LocalDate.now();
LocalTime localTime = LocalTime.now();
LocalDateTime localDateTime = LocalDateTime.now();
System.out.println("LocalDate 實例化輸出" + localDate);
System.out.println("LocalTime 實例化輸出" + localTime);
System.out.println("LocalDateTime 實例化輸出" + localDateTime);
System.out.println(String.format("當前日期%s-%s-%s", localDate.getYear(), localDate.getMonthValue(), localDate.getDayOfMonth()));
System.out.println("獲取一週的時間數" + localDate.getDayOfWeek().getValue());
System.out.println("今天所處的一月的週數" + localDate.get(ChronoField.ALIGNED_WEEK_OF_MONTH));
System.out.println("今天所處的一年的週數" + localDate.get(ChronoField.ALIGNED_WEEK_OF_YEAR));
System.out.println("今天所處的一年的第幾天" + localDate.getDayOfYear());
LocalDate localDate2 = LocalDate.parse("2020-04-02");
System.out.println("是否是閏年" + localDate2.isLeapYear());
System.out.println("所在月的第一天" + localDate.with(TemporalAdjusters.firstDayOfMonth()));
System.out.println("所在月的第一天" + localDate.withDayOfMonth(1));
System.out.println("所在月的最後一天" + localDate.with(TemporalAdjusters.lastDayOfMonth()));
System.out.println("三百年後的日期" + localDate.plusYears(300));
System.out.println("日期所處月的第一個週一" + localDate.with(TemporalAdjusters.firstInMonth(DayOfWeek.MONDAY)));
}
在多線程下的SimpleDateFormat類的操作:
首先說一下出現的原因:將字符串轉化爲日期,一定要使用SimpleDateFormat類,於是這個類成了所有項目開發中必然要採用的工具類,於是下面來針對這個工具類使用進行多線程環境下的分析:
單線程:
public static void main(String[] args) throws Exception{
for (int i = 0; i < 10; i++)
{
new Thread(() -> {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try {
System.out.println("當前線程的名稱是:" + Thread.currentThread().getName()+ " 線程id是:" + Thread.currentThread().getId() + sdf.parse("1998-02-17 22:31:32"));
} catch (ParseException e) {
e.printStackTrace();
}
}, "SDF轉換線程" + i).start();
}
}
上述代代碼,雖然也是多線程,但是每一個線程都保留了一個各自的SimpleDateFormat 類的對象,所以整個的轉換是可以正常完成的,但是上述多個線程要將字符串轉化爲相同的類型的日期,所以沒有必要每個線程都定義一個單獨的SimpleDateFormat 類對象實例(這樣可以減少內存垃圾內存開銷)
所以我們可以修改代碼(注意下面這代碼是錯誤的,給大家演示現象,危險代碼請勿模仿,這個錯誤時:將字符串轉化爲日期會報錯,但是當日期轉化爲字符串時不會報錯)
public static void main(String[] args) throws Exception{
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
for (int i = 0; i < 10; i++)
{
new Thread(() -> {
try {
System.out.println("當前線程的名稱是:" + Thread.currentThread().getName()+ " 線程id是:" + Thread.currentThread().getId() + sdf.parse("1998-02-17 22:31:32"));
} catch (ParseException e) {
e.printStackTrace();
}
}, "SDF轉換線程" + i).start();
}
}
發現代碼不僅報錯,而且有的時間不對
爲什麼會報錯:
出現的異常中有 NumberFormatException這個異常,是因爲在設計SimpleDateFormat類的時候,它的轉化處理操作機制並沒有同步的處理,即線程A的日期時間傳遞過來之後,可能剛配置了一半數據之後,線程B又傳過來的數據,也進行了匹配內容的變更,這樣就會出現線程不同步的問題。
即多個線程不能併發的訪問
如何解決這個問題的方法
1:傳統方法,每個線程都有一個SimpleDateFormat 對象,就是我們最開始的那種方法,但是缺點就是造垃圾
2:我們利用jdk1.8 的LocalDate ,LocalDateTime LocalDateTime 類來完成
public static void main(String[] args) throws Exception{
// 創建日期的格式化類對象,定義SimpleDateFormat 類中的匹配日期時間字符串
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
ZoneId zoneId = ZoneId.systemDefault();
for (int i = 0; i < 10; i++)
{
new Thread(() -> {
try {
LocalDateTime localDateTime = LocalDateTime.parse("1998-02-17 22:31:32", formatter);
Instant instant = localDateTime.atZone(zoneId).toInstant();// 獲得一個當前時區的一個實例
Date date = Date.from(instant);
System.out.println("當前線程的名稱是:" + Thread.currentThread().getName()+ " 線程id是:" + Thread.currentThread().getId()+ date);
} catch (Exception e) {
e.printStackTrace();
}
}, "SDF轉換線程" + i).start();
}
下面給出LocalDate 類
public static void main(String[] args) throws Exception{
// 創建日期的格式化類對象,定義SimpleDateFormat 類中的匹配日期時間字符串
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
ZoneId zoneId = ZoneId.systemDefault();
for (int i = 0; i < 10; i++)
{
new Thread(() -> {
try {
LocalDate localDate = LocalDate.parse("1998-02-17", formatter);
Instant instant = localDate.atStartOfDay().atZone(zoneId).toInstant();// 獲得一個當前時區的一個實例
Date date = Date.from(instant);
System.out.println("當前線程的名稱是:" + Thread.currentThread().getName()+ " 線程id是:" + Thread.currentThread().getId()+ date);
} catch (Exception e) {
e.printStackTrace();
}
}, "SDF轉換線程" + i).start();
}
}