1.背景
台北时区下,用户在客户端填写生日1979/08/01,客户端将1979/08/01 00:00:00(台北时区)转化为时间戳传给后端,后端在存储时,需解析出月份并单独保存到一个字段,用于生日券发放。接口在解析时用到北京时区,解析出的时间为1979/07/31 23:00:00(北京时区),所以该用户的月份字段值为7,得到了七月份生日券。
2.修改方案
取客户选择的日期+00:00:00(0时区),将该时间转化为时间戳传给后端,这样后端转化时,不会再出现日期不一致的情况。
3.实现步骤
Date date = new Date(); //模拟用户填写的日期
Calendar cd = Calendar.getInstance();
cd.setTime(date);
cd.setTimeZone(TimeZone.getTimeZone("UTC")); //设置时区
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
simpleDateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
//获取年月日,重置时分秒
cd.set(cd.get(Calendar.YEAR), cd.get(Calendar.MONTH), cd.get(Calendar.DATE), 0, 0, 0);
System.out.println(simpleDateFormat.format(cd.getTimeInMillis())); //输出2022-07-13 00:00:00
System.out.println(cd.getTimeInMillis()); //输出1657670400490
4.遇到的坑
System.out.println(simpleDateFormat.format(cd.getTimeInMillis())); //输出2022-07-13 00:00:00
System.out.println(cd.getTimeInMillis()); //输出1657670400490
此时转换后得到的时间戳存在毫秒级的误差 1657670400490
添加以下
cd.set(Calendar.MILLISECOND, 0); //单独设置毫秒,避免误差
得到
System.out.println(simpleDateFormat.format(cd.getTimeInMillis())); //2022-07-13 00:00:00
System.out.println(cd.getTimeInMillis()); //输出1657670400000
5.完整代码
Java
Date date = new Date(); //模拟用户填写的日期
Calendar cd = Calendar.getInstance();
cd.setTime(date);
cd.setTimeZone(TimeZone.getTimeZone("UTC")); //设置时区
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
simpleDateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
//获取年月日,重置时分秒
cd.set(cd.get(Calendar.YEAR), cd.get(Calendar.MONTH), cd.get(Calendar.DATE), 0, 0, 0);
cd.set(Calendar.MILLISECOND, 0); //单独设置毫秒,避免误差
System.out.println(simpleDateFormat.format(cd.getTimeInMillis())); //2022-07-13 00:00:00
System.out.println(cd.getTimeInMillis()); //输出1657670400000
Kotlin
val date = Date()
val cd = Calendar.getInstance()
cd.time = date
cd.timeZone = TimeZone.getTimeZone("UTC")
cd[cd[Calendar.YEAR], cd[Calendar.MONTH], cd[Calendar.DATE], 0, 0] = 0
cd[Calendar.MILLISECOND] = 0 //单独设置,避免毫秒级的误差
6.模拟
void testTime() {
for (int i = 0; i < 2023; i++) {
for (int j = 0; j < 12; j++) {
time(i, j);
}
}
}
private void time(int year, int month) {
Date date = new Date(); //模拟用户填写的日期 如果用电脑 就把电脑时区设置成台北 如果用手机 就设置手机时区
Calendar cd = Calendar.getInstance();
cd.setTime(date);
cd.set(year, month, 1, 0, 0, 0);
SimpleDateFormat simpleDateFormat1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
simpleDateFormat1.setTimeZone(TimeZone.getTimeZone("GMT+8:00"));
if (simpleDateFormat1.format(cd.getTimeInMillis()).contains("-31")){
System.out.println(simpleDateFormat1.format(cd.getTimeInMillis()));
System.out.println("");
}
}
结果
1900-01-31 23:54:17
1900-03-31 23:54:17
1900-05-31 23:54:17
1900-07-31 23:54:17
1900-08-31 23:54:17
1900-10-31 23:54:17
1919-05-31 23:00:00
1919-07-31 23:00:00
1919-08-31 23:00:00
1940-07-31 23:00:00
1940-08-31 23:00:00
1941-03-31 23:00:00
1941-05-31 23:00:00
1941-07-31 23:00:00
1941-08-31 23:00:00
1941-10-31 23:00:00
1942-01-31 23:00:00
1942-03-31 23:00:00
1942-05-31 23:00:00
1942-07-31 23:00:00
1942-08-31 23:00:00
1942-10-31 23:00:00
1942-12-31 23:00:00
1943-01-31 23:00:00
1943-03-31 23:00:00
1943-05-31 23:00:00
1943-07-31 23:00:00
1943-08-31 23:00:00
1943-10-31 23:00:00
1943-12-31 23:00:00
1944-01-31 23:00:00
1944-03-31 23:00:00
1944-05-31 23:00:00
1944-07-31 23:00:00
1944-08-31 23:00:00
1944-10-31 23:00:00
1944-12-31 23:00:00
1945-01-31 23:00:00
1945-03-31 23:00:00
1945-05-31 23:00:00
1945-07-31 23:00:00
1945-08-31 23:00:00
1946-05-31 23:00:00
1946-07-31 23:00:00
1946-08-31 23:00:00
1947-05-31 23:00:00
1947-07-31 23:00:00
1947-08-31 23:00:00
1948-05-31 23:00:00
1948-07-31 23:00:00
1948-08-31 23:00:00
1986-05-31 23:00:00
1986-07-31 23:00:00
1986-08-31 23:00:00
1987-05-31 23:00:00
1987-07-31 23:00:00
1987-08-31 23:00:00
1988-05-31 23:00:00
1988-07-31 23:00:00
1988-08-31 23:00:00
1989-05-31 23:00:00
1989-07-31 23:00:00
1989-08-31 23:00:00
1990-05-31 23:00:00
1990-07-31 23:00:00
1990-08-31 23:00:00
1991-05-31 23:00:00
1991-07-31 23:00:00
1991-08-31 23:00:00