前言
日常开发中我们经常涉及到对日期的处理,这篇博客整理了常用的日期处理方法。
代码实现:
import lombok.extern.slf4j.Slf4j;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
@Slf4j
public class DateUtils {
/**
* 将某格式的时间字符串转化成毫秒时间戳表示的字符串
*
* @param dateTime 时间字符串
* @param format 时间字符串的格式
* @return 毫秒时间戳表示的字符串,例如"1609459200000ms"
*/
// 将某格式的时间字符串转化成毫秒时间戳表示的字符串
public static String dateTimeStrToMills(String dateTime, String format) {
String dateStr = null;
SimpleDateFormat sdf = new SimpleDateFormat(format);
Calendar calendar = Calendar.getInstance();
calendar.clear();
try {
Date d = new Date();
d = sdf.parse(dateTime);
calendar.setTime(d);
dateStr = calendar.getTimeInMillis() + "ms";
} catch (ParseException e) {
e.printStackTrace();
}
return dateStr;
}
/**
* 将某格式的时间字符串转化成毫秒时间戳的长整型值
*
* @param dateTime 时间字符串
* @param format 时间字符串的格式
* @return 毫秒时间戳的长整型值
* @throws ParseException 如果输入的日期时间字符串格式不正确,则抛出此异常
*/
public static long dateTimeStrToMillsValue(String dateTime, String format) {
long dateValue = 0L;
SimpleDateFormat sdf = new SimpleDateFormat(format);
Calendar calendar = Calendar.getInstance();
calendar.clear();
try {
Date d = new Date();
d = sdf.parse(dateTime);
calendar.setTime(d);
dateValue = calendar.getTimeInMillis();
} catch (ParseException e) {
e.printStackTrace();
}
return dateValue;
}
/**
* 获取某个月的天数
*
* @param year 年份
* @param month 月份(从0开始计数,即1月对应0)
* @return 对应月份的天数
*/
public static int getDayNumOfMonth(int year, int month) {
Calendar calendar = Calendar.getInstance();
calendar.clear();
calendar.set(year, month, 0);
return calendar.get(Calendar.DAY_OF_MONTH);
}
/**
* 获取某日、月、年前后的日期
*
* @param num 表示要增加或减少的时间单位数量,正数表示未来的日期,负数表示过去的日期
* @param date 给定的日期字符串,格式需与format参数一致
* @param format 日期字符串的格式
* @param timeType 时间类型,可以是Calendar.YEAR(年)、Calendar.MONTH(月)、Calendar.DAY_OF_MONTH(日)等
* @return 计算后的日期字符串,格式与输入的date参数一致
* @throws ParseException 如果输入的日期字符串格式不正确,则抛出此异常
*/
public static String getBeforeOrAfterDateType(int num, String date, String format, int timeType) {
SimpleDateFormat sdf = new SimpleDateFormat(format);
String resultDate = "";
Calendar calendar = Calendar.getInstance();
calendar.clear();
try {
Date d = new Date();
d = sdf.parse(date);
calendar.setTime(d);
calendar.add(timeType, num);//一天的结束是第二天的开始
resultDate = sdf.format(calendar.getTime());
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return resultDate;
}
/**
* 根据毫秒时间戳获得格式化后的日期
*
* @param millisecond 毫秒时间戳
* @param dateFormat 日期格式,例如 "yyyy-MM-dd HH:mm:ss"
* @return 格式化后的日期字符串
*/
public static String millisecondToDate(Long millisecond, String dateFormat) {
Date date = new Date(millisecond);
GregorianCalendar gc = new GregorianCalendar();
gc.setTime(date);
SimpleDateFormat format = new SimpleDateFormat(dateFormat);
String sb = format.format(gc.getTime());
return sb;
}
/**
* 将毫秒时间戳转换为指定格式的日期字符串,并应用指定的时区。
*
* @param millisecond 毫秒时间戳
* @param dateFormat 日期格式,如 "yyyy-MM-dd HH:mm:ss"
* @param timeZoneId 时区ID,如 "GMT+8"
* @return 转换后的日期字符串
*/
public static String convertTimestampToFormattedDate(long millisecond, String dateFormat, String timeZoneId) {
Date date = new Date(millisecond);
GregorianCalendar gc = new GregorianCalendar();
gc.setTime(date);
SimpleDateFormat format = new SimpleDateFormat(dateFormat);
TimeZone timeZone = TimeZone.getTimeZone(timeZoneId);
format.setTimeZone(timeZone);
String sb = format.format(gc.getTime());
return sb;
}
/**
* 获取某月的第一天。
*
* @param year 年份
* @param month 月份(注意:月份从1开始计数,但Calendar类内部月份是从0开始计数的,因此需减1)
* @return 返回指定月份第一天的日期字符串,格式为"yyyy-MM-dd"
*/
public static String getFirstDayOfMonth(int year, int month) {
Calendar cal = Calendar.getInstance();
cal.set(Calendar.YEAR, year);
cal.set(Calendar.MONTH, month - 1);
int firstDay = cal.getActualMinimum(Calendar.DAY_OF_MONTH);
cal.set(Calendar.DAY_OF_MONTH, firstDay);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String firstDayOfMonth = sdf.format(cal.getTime());
return firstDayOfMonth;
}
/**
* 获取某月的最后一天。
*
* @param year 年份
* @param month 月份(注意:月份从1开始计数,但Calendar类内部月份是从0开始计数的,因此需减1)
* @param format 日期格式,例如 "yyyy-MM-dd"
* @return 返回指定月份最后一天的日期字符串,格式与输入的format参数一致
*/
public static String getLastDayOfMonth(int year, int month, String format) {
Calendar cal = Calendar.getInstance();
cal.clear();
cal.set(Calendar.YEAR, year);
cal.set(Calendar.MONTH, month - 1);
int lastDay = 0;
lastDay = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
cal.set(Calendar.DAY_OF_MONTH, lastDay);
SimpleDateFormat sdf = new SimpleDateFormat(format);
String lastDayOfMonth = sdf.format(cal.getTime());
return lastDayOfMonth;
}
/**
* 获取起止日期之间的所有日期字符串(可自定义间隔、格式、日期类型)
*
* @param begin 开始日期字符串
* @param end 结束日期字符串
* @param num 日期间隔数量
* @param timeType 日期类型,可以是Calendar.YEAR(年)、Calendar.MONTH(月)、Calendar.DAY_OF_MONTH(日)等
* @param format 日期字符串的格式
* @return 返回起止日期之间的所有日期字符串列表
* @throws ParseException 如果输入的日期字符串格式不正确,则抛出此异常
*/
public static List<String> getDatesBetweenTwoDate(String begin, String end, int num, int timeType, String format) {
List<String> lDates = new ArrayList<>();
if (begin.equals(end)) {
lDates.add(begin);
return lDates;
}
try {
SimpleDateFormat sdf = new SimpleDateFormat(format);
Date beginDate = sdf.parse(begin);
Date endDate = sdf.parse(end);
lDates.add(sdf.format(beginDate));
Calendar calendar = Calendar.getInstance();
calendar.setTime(beginDate);
boolean bContinue = true;
while (bContinue) {
calendar.add(timeType, num);
if (endDate.after(calendar.getTime())) {
lDates.add(sdf.format(calendar.getTime()));
} else {
break;
}
}
lDates.add(sdf.format(endDate));
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return lDates;
}
/**
* 获取当前日期和时间。
*
* @return 当前日期和时间的Date对象
* @throws ParseException 如果解析日期字符串时发生错误,则抛出此异常
*/
public static Date getCurrentDateTime() throws ParseException {
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = new Date();
return formatter.parse(formatter.format(date));
}
/**
* 获取当前日期和时间的字符串表示。
*
* @return 当前日期和时间的字符串表示,格式为"yyyy-MM-dd HH:mm:ss"
*/
public static String getCurrentDateTimeStr() {
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = new Date();
return formatter.format(date);
}
/**
* 将给定的Date对象转换为字符串形式。
*
* @param dateTime 要转换的Date对象
* @return 转换后的日期字符串,格式为"yyyy-MM-dd HH:mm:ss"
*/
public static String dateToString(Date dateTime) {
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String strDate = sdf2.format(dateTime);
return strDate;
}
/**
* 将给定时间转为太平洋时间(美国洛杉矶时间)。
*
* @param date 给定的时间,类型为Date
* @return 转换后的太平洋时间字符串,格式为"yyyy-MM-dd HH:mm:ss"
*/
public static String changeTimeToPacificTime(Date date) {
//将给定时间转为太平洋时间
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
sdf.setTimeZone(TimeZone.getTimeZone("America/Los_Angeles"));
String pacificTime = sdf.format(date);
return pacificTime;
}
/**
* 将太平洋时间(美国洛杉矶时间)转换为北京时间。
*
* @param time 太平洋时间字符串,格式为"yyyy-MM-dd HH:mm:ss"
* @return 转换后的北京时间字符串,格式为"yyyy-MM-dd HH:mm:ss"
* @throws RuntimeException 如果输入的太平洋时间字符串格式不正确,则抛出此异常
*/
public static String changePacificTimeToCST(String time) {
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
sdf2.setTimeZone(TimeZone.getTimeZone("America/Los_Angeles"));
Date date = null;
try {
date = sdf2.parse(time);
} catch (ParseException e) {
throw new RuntimeException(e);
}
//将太平洋时间转成北京时间
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String cstTime = sdf.format(date);
return cstTime;
}
/**
* 将太平洋时间(美国洛杉矶时间)转换为UTC时间。
*
* @param time 太平洋时间字符串,格式为"yyyy-MM-dd HH:mm:ss"
* @return 转换后的UTC时间字符串,格式为"dd/MM/yyyy"
* @throws RuntimeException 如果输入的太平洋时间字符串格式不正确,则抛出此异常
*/
public static String changePacificTimeToUTC(String time) {
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
sdf2.setTimeZone(TimeZone.getTimeZone("America/Los_Angeles"));
Date date = null;
try {
date = sdf2.parse(time);
} catch (ParseException e) {
throw new RuntimeException(e);
}
//将太平洋时间转成北京时间
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
return sdf.format(date);
}
/**
* 将给定的太平洋时间字符串转换为时间戳。
*
* @param time 太平洋时间字符串,格式为"yyyy-MM-dd HH:mm:ss"
* @return 转换后的时间戳
* @throws RuntimeException 如果输入的太平洋时间字符串格式不正确,则抛出此异常
*/
public static long getPacificTimeTimestamp(String time) {
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
sdf2.setTimeZone(TimeZone.getTimeZone("America/Los_Angeles"));
Date date = null;
long timestamp;
try {
date = sdf2.parse(time);
timestamp = date.getTime();
} catch (ParseException e) {
throw new RuntimeException(e);
}
return timestamp;
}
/**
* 将给定的时间字符串转换为时间戳。
*
* @param time 时间字符串,格式为"yyyy-MM-dd HH:mm:ss"
* @return 转换后的时间戳
* @throws RuntimeException 如果输入的时间字符串格式不正确,则抛出此异常
*/
public static long getCSTTimestamp(String time) {
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = null;
long timestamp;
try {
date = sdf2.parse(time);
timestamp = date.getTime();
} catch (ParseException e) {
throw new RuntimeException(e);
}
return timestamp;
}
/**
* 将字符串转换为日期对象。
*
* @param dateStr 要转换的日期字符串
* @param format 日期字符串的格式
* @return 转换后的日期对象,如果转换失败则返回null
*/
public static Date StringToDate(String dateStr, String format) {
SimpleDateFormat dateFormat = new SimpleDateFormat(format);
Date date = null;
try {
date = dateFormat.parse(dateStr);
} catch (ParseException ex) {
ex.printStackTrace();
}
return date;
}
/**
* 获取月环比的时间段。
*
* @param startTime 开始时间字符串
* @param endTime 结束时间字符串
* @param format 日期格式
* @return 包含环比开始时间和结束时间的Map,键分别为"comparedStartTime"和"comparedEndTime"
*/
public static Map<String, String> getMoMTimePeriod(String startTime, String endTime, String format) {
// 计算出两个用户日期之间相隔多少天,然后开始时间往前按间隔得到环比的开始时间,环比结束时间为开始时间的前一天
Map<String, String> result = new HashMap<>();
List<String> dates = getDatesBetweenTwoDate(startTime, endTime, 1, Calendar.DAY_OF_MONTH, format);
int intervalDay = dates.size();
result.put("comparedStartTime", getBeforeOrAfterDateType(-intervalDay, startTime, format, Calendar.DAY_OF_MONTH));
result.put("comparedEndTime", getBeforeOrAfterDateType(-1, startTime, format, Calendar.DAY_OF_MONTH));
return result;
}
/**
* 获取当前时间的UTC/GMT时间字符串。
*
* @return 返回当前时间的UTC/GMT时间字符串,格式为"EEE, d MMM yyyy HH:mm:ss 'GMT'"
*/
public static String getUTCGMTTimeStr() {
Calendar cd = Calendar.getInstance();
SimpleDateFormat sdf = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss 'GMT'", Locale.US);
sdf.setTimeZone(TimeZone.getTimeZone("GMT")); // 设置时区为GMT
String str = sdf.format(cd.getTime());
return str;
}
/**
* 将给定的Date对象转换为日期字符串。
*
* @param date 要转换的Date对象
* @return 转换后的日期字符串,格式为"dd/MM/yyyy"
*/
public static String getDateStr(Date date) {
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy", Locale.US);
String str = sdf.format(date);
return str;
}
// 获取当天零点时间戳-----Proxy为Remo获取太平洋时间当天零点时间戳,Proxy为Korea获取首尔时间当天零点时间戳
public static Long getZeroTimestampMillis(String proxy) {
// 获取当前北京时间的毫秒级时间戳
Instant currentInstant = Instant.now();
if ("Korea".equals(proxy)) {
// 将时间戳转换为韩国首尔时间的当天零点的毫秒级时间戳
ZoneId seoulZone = ZoneId.of("Asia/Seoul");
ZonedDateTime seoulDateTime = currentInstant.atZone(seoulZone).toLocalDate().atStartOfDay(seoulZone);
long seoulZeroTimestampMillis = seoulDateTime.toInstant().toEpochMilli();
return seoulZeroTimestampMillis;
} else {
// 将时间戳转换为太平洋时间的当天零点的毫秒级时间戳
ZoneId pacificZone = ZoneId.of("America/Los_Angeles");
ZonedDateTime pacificDateTime = currentInstant.atZone(pacificZone).toLocalDate().atStartOfDay(pacificZone);
long pacificZeroTimestampMillis = pacificDateTime.toInstant().toEpochMilli();
return pacificZeroTimestampMillis;
}
}
public static DayTimestamp getDayStartAndEndTimestamp(Long timestamp, String proxy) {
DayTimestamp result = new DayTimestamp();
// 获取当前北京时间的毫秒级时间戳
if (timestamp == null) {
timestamp = System.currentTimeMillis();
}
Instant currentInstant = Instant.ofEpochMilli(timestamp);
if ("Korea".equals(proxy)) {
result.setProxy("Korea");
// 将时间戳转换为韩国首尔时间的当天零点的毫秒级时间戳
ZoneId seoulZone = ZoneId.of("Asia/Seoul");
LocalDateTime seoulDateTime = currentInstant.atZone(seoulZone).toLocalDateTime();
LocalDateTime seoulStartOfDay = seoulDateTime.toLocalDate().atStartOfDay();
LocalDateTime seoulEndOfDay = seoulStartOfDay.plusDays(1).minus(1, ChronoUnit.SECONDS);
long seoulStartOfDayTimestamp = seoulStartOfDay.atZone(seoulZone).toInstant().toEpochMilli();
long seoulEndOfDayTimestamp = seoulEndOfDay.atZone(seoulZone).toInstant().toEpochMilli();
result.setStartOfDayTimestamp(seoulStartOfDayTimestamp);
result.setEndOfDayTimestamp(seoulEndOfDayTimestamp);
} else {
result.setProxy("Remo");
// 将时间戳转换为太平洋时间的当天零点的毫秒级时间戳
ZoneId pacificZone = ZoneId.of("America/Los_Angeles");
LocalDateTime pacificDateTime = currentInstant.atZone(pacificZone).toLocalDateTime();
LocalDateTime pacificStartOfDay = pacificDateTime.toLocalDate().atStartOfDay();
LocalDateTime pacificEndOfDay = pacificStartOfDay.plusDays(1).minus(1, ChronoUnit.SECONDS);
long pacificStartOfDayTimestamp = pacificStartOfDay.atZone(pacificZone).toInstant().toEpochMilli();
long pacificEndOfDayTimestamp = pacificEndOfDay.atZone(pacificZone).toInstant().toEpochMilli();
result.setStartOfDayTimestamp(pacificStartOfDayTimestamp);
result.setEndOfDayTimestamp(pacificEndOfDayTimestamp);
}
return result;
}
/**
* 找到并返回下一个周五的日期字符串。
*
* @return 下一个周五的日期字符串,格式为 yyyy-MM-dd
*/
public static String findNearestFriday() {
LocalDate currentDate = LocalDate.now();
DayOfWeek currentDayOfWeek = currentDate.getDayOfWeek();
// 计算到下一个周五还有几天
int daysUntilNextFriday = DayOfWeek.FRIDAY.getValue() - currentDayOfWeek.getValue();
if (daysUntilNextFriday <= 0) {
daysUntilNextFriday += 7; // 如果今天就是周五,则加一周
}
// 加上天数得到下一个周五的日期
LocalDate nextFriday = currentDate.plusDays(daysUntilNextFriday);
return nextFriday.toString(); // 返回格式化的日期字符串,格式为 yyyy-MM-dd
}
/**
* 根据给定的日期字符串,获取该日期所在周的周一日期字符串。
*
* @param dateStr 日期字符串,格式为"yyyy-MM-dd"
* @return 返回该日期所在周的周一日期字符串,格式也为"yyyy-MM-dd"
*/
public static String getWeekStrByDayStr(String dateStr) {
String dateValue = null;
String week = DateUtils.getWeek(DateUtils.StringToDate(dateStr, "yyyy-MM-dd"));
int interval = DateUtils.getIntervalFromMonday(week);
if (interval == 0) {
dateValue = dateStr;
} else {
dateValue = DateUtils.getBeforeOrAfterDateType(interval, dateStr, "yyyy-MM-dd", Calendar.DAY_OF_MONTH);
}
return dateValue;
}
/**
* 获取给定日期是星期几。
*
* @param date 给定的日期
* @return 返回给定日期是星期几,用英文缩写表示(例如:"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat")
*/
public static String getWeek(Date date) {
String[] weeks = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
Calendar cal = Calendar.getInstance();
cal.setTime(date);
int week_index = cal.get(Calendar.DAY_OF_WEEK) - 1;
if (week_index < 0) {
week_index = 0;
}
return weeks[week_index];
}
/**
* 根据给定的星期几,计算距离周一的天数间隔。
*
* @param week 给定的星期几,用英文缩写表示(例如:"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat")
* @return 返回距离周一的天数间隔,周一返回0,周二返回-1,周三返回-2,以此类推
*/
public static int getIntervalFromMonday(String week) {
if ("Tue".equals(week)) {
return -1;
} else if ("Wed".equals(week)) {
return -2;
} else if ("Thu".equals(week)) {
return -3;
} else if ("Fri".equals(week)) {
return -4;
} else if ("Sat".equals(week)) {
return -5;
} else if ("Sun".equals(week)) {
return -6;
}
return 0;
}
/**
* 根据给定的月份字符串,获取该月份所在的季度字符串。
*
* @param dateStr 日期字符串,格式为"yyyy-MM"
* @return 返回该月份所在的季度字符串,格式为"yyyy-MM",其中MM为季度的起始月份
*/
public static String getQuarterStrByMonthStr(String dateStr) {
String dateValue = null;
String subYear = dateStr.substring(0, 4);
String monthStr = dateStr.substring(5);
if ("01".equals(monthStr) || "02".equals(monthStr) || "03".equals(monthStr)) {
dateValue = subYear + "-" + "01";
} else if ("04".equals(monthStr) || "05".equals(monthStr) || "06".equals(monthStr)) {
dateValue = subYear + "-" + "04";
} else if ("07".equals(monthStr) || "08".equals(monthStr) || "09".equals(monthStr)) {
dateValue = subYear + "-" + "07";
} else if ("10".equals(monthStr) || "11".equals(monthStr) || "12".equals(monthStr)) {
dateValue = subYear + "-" + "10";
}
return dateValue;
}
/**
* 根据给定的时间戳、代理和类型,获取太平洋时间当天开始和结束的时间戳。
*
* @param timestamp 给定的时间戳,如果为null,则使用当前系统时间
* @param proxy 代理类型,用于确定时区("Korea"表示韩国首尔时间,"其他"表示美国洛杉矶时间)
* @param type 类型,用于确定返回当天开始时间戳还是结束时间戳("startTime"表示开始时间戳,"其他"表示结束时间戳)
* @return 返回太平洋时间当天开始或结束的时间戳
*/
public static Long getDayStartAndEndTimestamp(Long timestamp, String proxy, String type) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
// 将时间戳转换为Date对象
Date date = new Date(timestamp);
//获取北京时间字符串
String dateStr = sdf.format(date);
// 获取当前北京时间的毫秒级时间戳
if (timestamp == null) {
timestamp = System.currentTimeMillis();
}
Instant currentInstant = Instant.ofEpochMilli(timestamp);
}
/**
* 根据给定的日期字符串,获取太平洋时区该日期当天的开始时间戳(午夜00:00)。
*
* @param dateStr 日期字符串,格式为ISO 8601标准(例如:"2023-10-05")
* @return 返回太平洋时区该日期当天的开始时间戳(以毫秒为单位)
*/
public static long getPacificZoneStartTimestampByDateStr(String dateStr) {
// 解析日期字符串为LocalDate对象
LocalDate date = LocalDate.parse(dateStr, DateTimeFormatter.ISO_LOCAL_DATE);
// 指定目标时区为太平洋时区
ZoneId pacificZone = ZoneId.of("America/Los_Angeles");
// 创建ZonedDateTime对象,将日期和时间设为午夜(00:00)
ZonedDateTime zonedDateTime = ZonedDateTime.of(date, LocalTime.MIDNIGHT, pacificZone);
// 转换为Instant对象(获取时间戳)
Instant instant = zonedDateTime.toInstant();
long timestamp = instant.toEpochMilli();
return timestamp;
}
}