01-date
1. mysql
1. date_format()
select now();
-- 24小时制 (2024-03-22 07:49:47)
select date_format(now(), '%Y-%m-%d %T');
-- 24小时制 (2024-03-22 07:49:47)
select date_format(now(), '%Y-%m-%d %H:%i:%s');
-- 05:06:07 (24小时制)
select date_format('2000-05-07 13:06:07', '%H:%i:%s');
-- 05:06:07 (12小时制)
select date_format('2000-05-07 13:06:07', '%h:%i:%s');
格式 | 描述 | 格式 | 描述 |
---|---|---|---|
%a | 缩写星期名 | %p | AM 或 PM |
%b | 缩写月名 | %r | 时间,12-小时(hh:mm:ss AM 或 PM) |
%c | 月,数值 | %S | 秒(00-59) |
%D | 带有英文前缀的月中的天 | %s | 秒(00-59) |
%d | 月的天,数值(00-31) | %T | 时间, 24-小时 (hh:mm:ss) |
%e | 月的天,数值(0-31) | %U | 周 (00-53) 星期日是一周的第一天 |
%f | 微秒 | %u | 周 (00-53) 星期一是一周的第一天 |
%H | 小时 (00-23) | %V | 周 (01-53) 星期日是一周的第一天,与 %X 使用 |
%h | 小时 (01-12) | %v | 周 (01-53) 星期一是一周的第一天,与 %x 使用 |
%I | 小时 (01-12) | %W | 星期名 |
%i | 分钟,数值(00-59) | %w | 周的天 (0=星期日, 6=星期六) |
%j | 年的天 (001-366) | %X | 年,其中的星期日是周的第一天,4 位,与 %V 使用 |
%k | 小时 (0-23) | %x | 年,其中的星期一是周的第一天,4 位,与 %v 使用 |
%l | 小时 (1-12) | %Y | 年,4 位 |
%M | 月名 | %y | 年,2 位 |
%m | 月,数值(00-12) |
2. between_and
# between_and 包含边界 (b <= x <= a)
# 1. '2024-04-09' 默认是 '2024-04-09 00:00:00'
# 2. (date, datetime, timestamp) 最大处理精度为(年-月-日)
# 3. 当月
select *
from tmp
where updtime like '2024-04-08%';
select *
from tmp
where date_format(updtime, '%Y-%m') like '2024-04';
# 4. 月末日期
select last_day(now()); # 2024-04-30
# 5. 月初日期
select date_format(now(), '%Y-%m-01');
# 6. 区间范围 updtime = 2024-04-08 01:16:42
# 查不到
select *
from tmp
where updtime between '2024-04-07 01:16:42' and '2024-04-08';
# 精确范围
select *
from tmp
where updtime between '2024-04-07 01:16:42' and '2024-04-08 23:59:59';
# 只查日期
select *
from tmp
where date(updtime) between '2024-04-07' and '2024-04-08';
2. java
1. 当前日期、时间
// 当前时间
Date date = DateUtil.date();
// 当前时间
Date date2 = DateUtil.date(Calendar.getInstance());
// 当前时间
Date date3 = DateUtil.date(System.currentTimeMillis());
// 当前时间字符串。yyyy-MM-dd HH:mm:ss
String now = DateUtil.now();
// 当前日期字符串。yyyy-MM-dd
String today = DateUtil.today();
2. 字符串转日期
DateUtil.parse()
会自动识别一些常用格式:
- yyyy-MM-dd HH:mm:ss
- yyyy/MM/dd HH:mm:ss
- yyyy.MM.dd HH:mm:ss
- yyyy年MM月dd日 HH时mm分ss秒
- yyyy-MM-dd
- yyyy/MM/dd
- yyyy.MM.dd
- HH:mm:ss
- HH时mm分ss秒
- yyyy-MM-dd HH:mm
- yyyy-MM-dd HH:mm:ss.SSS
- yyyyMMddHHmmss
- yyyyMMddHHmmssSSS
- yyyyMMdd
- EEE, dd MMM yyyy HH:mm:ss z
- EEE MMM dd HH:mm:ss zzz yyyy
- yyyy-MM-dd'T'HH:mm:ss'Z'
- yyyy-MM-dd'T'HH:mm:ss.SSS'Z'
- yyyy-MM-dd'T'HH:mm:ssZ
- yyyy-MM-dd'T'HH:mm:ss.SSSZ
String dateStr = "2017-03-01";
Date date = DateUtil.parse(dateStr);
// 自定义日期格式转化
String dateStr = "2017-03-01";
Date date = DateUtil.parse(dateStr, "yyyy-MM-dd");
3. 日期转字符串
// 2017/03/01
String format = DateUtil.format(new Date(), "yyyy/MM/dd");
String format = DateUtil.format(new Date(), "yyyy-MM-ddHH:mm:ss");
// yyyy-MM-dd
String format = DateUtil.format(new Date(), DatePattern.NORM_DATE_PATTERN);
// ------------------------------------------------------------------
// 2017-03-01 00:00:00
String formatDateTime = DateUtil.formatDateTime(date);
// 2017-03-01
String formatDate = DateUtil.formatDate(date);
// 00:00:00
String formatTime = DateUtil.formatTime(date);
4. Date对象的某个部分
Date date = DateUtil.date();
// 年
DateUtil.year(date);
// 月份,从0开始计数
DateUtil.month(date);
// 月份枚举
DateUtil.monthEnum(date);
// 年中第几天
int x = DateUtil.dayOfYear(date);
// 月中第几天
int y = DateUtil.dayOfMonth(date);
// 星期中第几天,星期日是第一天
int z = DateUtil.dayOfWeek(date);
5. 开始、结束时间
String dateStr = "2017-03-22 22:33:23";
Date date = DateUtil.parse(dateStr);
// 一天的开始 (2017-03-22 00:00:00)
Date beginOfDay = DateUtil.beginOfDay(date);
// 一天的结束 (2017-03-22 23:59:59)
Date endOfDay = DateUtil.endOfDay(date);
// 月初 (2017-03-01 00:00:00)
DateTime beginOfMonth = DateUtil.beginOfMonth(date);
// 月末 (2017-03-31 23:59:59)
DateTime endOfMonth = DateUtil.endOfMonth(date);
// 年初 (2017-01-01 00:00:00)
DateTime beginOfYear = DateUtil.beginOfYear(date);
// 年末 (2017-12-31 23:59:59)
DateTime endOfYear = DateUtil.endOfYear(date);
6. 日期时间偏移
- 日期、时间的偏移指针,对某个日期 (+、-) 分、小时、天等等,进行日期变更
String dateStr = "2017-03-01 22:33:23";
Date date = DateUtil.parse(dateStr);
// 日期:2017-03-03 22:33:23
Date newDate = DateUtil.offset(date, DateField.DAY_OF_MONTH, 2);
// 日期:2017-03-04 22:33:23
DateTime newDate2 = DateUtil.offsetDay(date, 3);
// 小时:2017-03-01 19:33:23
DateTime newDate3 = DateUtil.offsetHour(date, -3);
- 针对当前时间,提供了简化的偏移方法
// 昨天
DateUtil.yesterday()
// 明天
DateUtil.tomorrow()
// 上周
DateUtil.lastWeek()
// 下周
DateUtil.nextWeek()
// 上个月
DateUtil.lastMonth()
// 下个月
DateUtil.nextMonth()
7. 日期时间差
- 相差天数、相差小时数
String dateStr1 = "2017-03-01 22:33:23";
Date date1 = DateUtil.parse(dateStr1);
String dateStr2 = "2017-04-01 23:33:23";
Date date2 = DateUtil.parse(dateStr2);
// 相差一个月,31天。相差24h是一天
long betweenDay = DateUtil.between(date1, date2, DateUnit.DAY);
8. 格式化时间差
- 易读的时间差,eg:
XX天XX小时XX分XX秒
,此时使用DateUtil.formatBetween
方法:
Date startDate = DateUtil.parse("2021-04-20 02:00:00");
Date endDate = DateUtil.parse("2021-04-21 05:10:25");
// Level.SECOND表示精确到秒
String formatBetween = DateUtil.formatBetween(startDate, endDate, BetweenFormatter.Level.SECOND);
// formatBetween: 1天3小时10分25秒
System.out.println("formatBetween = " + formatBetween);
// betweenMS:毫秒
String formatBetween = DateUtil.formatBetween(betweenMS, BetweenFormatter.Level.SECOND);
9. 星座和属相
// "摩羯座"
String zodiac = DateUtil.getZodiac(Month.JANUARY.getValue(), 19);
// "狗"
String chineseZodiac = DateUtil.getChineseZodiac(1994);
10. 日期范围
// 创建日期范围生成器
DateTime start = DateUtil.parse("2021-01-31 13:29:29");
DateTime end = DateUtil.parse("2021-05-31 13:29:10");
DateRange range = DateUtil.range(start, end, DateField.MONTH);
range.forEach(System.out::println);
System.out.println("--------------------------------------------------");
// 区间 [2021-01-31 13:29:29, 2021-03-31 13:29:29]
List<DateTime> dateTimes = DateUtil.rangeToList(start, end, DateField.MONTH, 2);
System.out.println("dateTimes = " + dateTimes);
System.out.println("--------------------------------------------------");
// 开始时间
DateRange startRange = DateUtil.range(DateUtil.parse("2017-01-01"), DateUtil.parse("2017-01-31"), DateField.DAY_OF_YEAR);
// 结束时间
DateRange endRange = DateUtil.range(DateUtil.parse("2017-01-31"), DateUtil.parse("2017-02-02"), DateField.DAY_OF_YEAR);
// 交集 [2017-01-31 00:00:00]
List<DateTime> rangeContains = DateUtil.rangeContains(startRange, endRange);
System.out.println("rangeContains = " + rangeContains);
System.out.println("----------------------- DateRange上一步影响了游标 ---------------------------");
// 差集 [2017-02-01 00:00:00, 2017-02-02 00:00:00]
List<DateTime> rangeNotContains = DateUtil.rangeNotContains(startRange, endRange);
System.out.println("rangeNotContains = " + rangeNotContains);
2021-01-31 13:29:29
2021-02-28 13:29:29
2021-03-31 13:29:29
2021-04-30 13:29:29
--------------------------------------------------
dateTimes = [2021-01-31 13:29:29, 2021-03-31 13:29:29]
--------------------------------------------------
rangeContains = [2017-01-31 00:00:00]
----------------------- DateRange上一步影响了游标 ---------------------------
rangeNotContains = []
11. 其它
// 年龄
int age = DateUtil.ageOfNow("1994-10-18");
// 是否闰年
boolean leapYear = DateUtil.isLeapYear(2017);
3. 常见问题
1. YYYY、yyyy区别
YYYY
:当天所在的周属于的年份。一周从周日开始,周六结束,只要本周跨年,那么这周就算进入下一年yyyy
:四位年份
Calendar calendar = Calendar.getInstance();
calendar.set(2019, Calendar.DECEMBER, 31);
Date testDate = calendar.getTime();
SimpleDateFormat dtf = new SimpleDateFormat("YYYY-MM-dd");
// 2019-12-31 转`YYYY-MM-dd`格式后: 2020-12-31
System.out.println("2019-12-31 转`YYYY-MM-dd`格式后: " + dtf.format(testDate));
2. HH、hh区别
HH
:24小时制hh
:12小时制。当时间为12点,处理为0点
String str = "2020-03-18 12:00";
SimpleDateFormat dtf = new SimpleDateFormat("yyyy-MM-dd hh:mm");
Date newDate = dtf.parse(str);
// Wed Mar 18 00:00:00 CST 2020
System.out.println("newDate = " + newDate);
3. SimleDateFormat
1. format初始化问题
- 用format格式化日期是,要输入的是一个
Date
日期,而不是整型、字符串
SimpleDateFormat dtf = new SimpleDateFormat("yyyy-MM-dd");
String format = dtf.format(20200323);
// format = 1970-01-01
System.out.println("format = " + format);
Calendar calendar = Calendar.getInstance();
calendar.set(2020, Calendar.MARCH, 23);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String format = sdf.format(calendar.getTime());
System.out.println("format = " + format);
2. 线程不安全
- 将
SimpleDateFormat
定义为局部变量 - 使用
ThreadLocal
- 方法加同步锁
synchronized
- 直接使用
DateTimeFromatter
public class SimpleDateFormatTest {
private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
public static void main(String[] args) {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 100, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(1_000));
while (true) {
threadPoolExecutor.execute(() -> {
String dateString = sdf.format(new Date());
try {
Date parseDate = sdf.parse(dateString);
String dateString2 = sdf.format(parseDate);
System.out.println(dateString.equals(dateString2));
} catch (ParseException e) {
e.printStackTrace();
}
});
}
}
}
Exception in thread "pool-1-thread-49" java.lang.NumberFormatException: For input string: "5151."
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Long.parseLong(Long.java:589)
at java.lang.Long.parseLong(Long.java:631)
at java.text.DigitList.getLong(DigitList.java:195)
at java.text.DecimalFormat.parse(DecimalFormat.java:2051)
at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:2162)
at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1514)
at java.text.DateFormat.parse(DateFormat.java:364)
at com.example.demo.SimpleDateFormatTest.lambda$main$0(SimpleDateFormatTest.java:19)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Exception in thread "pool-1-thread-47" java.lang.NumberFormatException: For input string: "5151."
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Long.parseLong(Long.java:589)
at java.lang.Long.parseLong(Long.java:631)
at java.text.DigitList.getLong(DigitList.java:195)
at java.text.DecimalFormat.parse(DecimalFormat.java:2051)
at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:2162)
at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1514)
at java.text.DateFormat.parse(DateFormat.java:364)
at com.example.demo.SimpleDateFormatTest.lambda$main$0(SimpleDateFormatTest.java:19)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
4. DateTimeFormatter
DateTimeFormatter 这个类默认进行本地化设置,如果默认是中文,解析英文字符串就会报异常。可以传入一个本地化参数(Locale.US)解决
String dateStr = "Wed Mar 18 10:00:00 2020";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss yyyy", Locale.CHINA);
// DateTimeFormatter formatter = DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss yyyy", Locale.US);
LocalDateTime dateTime = LocalDateTime.parse(dateStr, formatter);
System.out.println("dateTime = " + dateTime);
5. Calendar设置时间
Calendar.HOUR 默认是按12小时制处理
Calendar.HOUR_OF_DAY,才是按24小时处理
Calendar c = Calendar.getInstance();
c.set(Calendar.HOUR, 10);
// c.set(Calendar.HOUR_OF_DAY, 10);
// c.getTime() = Sun Mar 24 22:52:58 CST 2024
System.out.println("c.getTime() = " + c.getTime());
6. 日期计算
得到的日期居然比当前日期还要早,根本不是晚 30 天的时间。因为发生了
int
发生了溢出
Date today = new Date();
// int溢出
Date nextMonth = new Date(today.getTime() + 30 * 1_000 * 60 * 60 * 24);
System.out.println("nextMonth = " + nextMonth);
LocalDateTime now = LocalDateTime.now();
LocalDateTime localDateTime = now.plusDays(30);
System.out.println("localDateTime = " + localDateTime);
7. 夏令时问题
- 夏令时,表示为了节约能源,人为规定时间的意思
- 一般在天亮早的夏季人为将时间调快一小时,可以使人早起早睡,减少照明量,以充分利用光照资源,从而节约照明用电
- 各个采纳夏时制的国家具体规定不同。目前全世界有近
110
个国家每年要实行夏令时 1986年4月
,中国中央有关部门发出“在全国范围内实行夏时制的通知”,具体作法是:每年从四月中旬第一个星期日的凌晨2时整(北京时间),将时钟拨快一小时。(1992
年起,夏令时暂停实行)- 夏时令这几个时间可以注意一下:
1986-05-04, 1987-04-12, 1988-04-10, 1989-04-16, 1990-04-15, 1991-04-14
TimeZone.setDefault(TimeZone.getTimeZone("Asia/Shanghai"));
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// Sun May 04 01:30:00 CDT 1986
System.out.println(sdf.parse("1986-05-04 00:30:00"));
- 中国在
1986-05-04
当天还在使用夏令时,时间被拨快了1
个小时。所以0点30分
打印成了1点30分
。修改时区为东8区
TimeZone.setDefault(TimeZone.getTimeZone("GMT+8"));
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println(sdf.parse("1986-05-04 00:30:00"));