最后
手绘了下图所示的kafka知识大纲流程图(xmind文件不能上传,导出图片展现),但都可提供源文件给每位爱学习的朋友
}
} catch (IOException ex) {
throw new DateTimeException(ex.getMessage(), ex);
}
}
**formatTo(temporal, buf)**方法也是先判断两个入参空处理。
然后,Instant对象被封装在一个新new的DateTimePrintContext对象
运行demo有问题,进行排查
//根据特定格式格式化日期
DateTimeFormatter dtf = DateTimeFormatter.ofPattern(“yyyy-MM-dd”);
String dateStr = DateUtil.format(new Date(),dtf);
System.out.println(dateStr);
到这里已经是jdk的源码了DateTimeFormatter.format
从上面可知,会调用 NumberPrinterParser.format() NumberPrinterParser是在DateTimeFormatterBuilder类中的。
到这一步会报错
为什么会报错呢,我们来看下context.getValue(field)发生了什么:
从上面代码可行,temporal实际上是Instant对象,Instant.getLong只支持四种字段类型。。
NANO_OF_SECOND
MICRO_OF_SECOND
MILLI_OF_SECOND
INSTANT_SECONDS
如果不是上面这几种字段类型,则抛出异常
DateUtil.format当遇到DateTimeFormatter会将Date对象首先转换为Instant,因为缺少时区,导致报错。
/**
-
根据特定格式格式化日期
-
@param date 被格式化的日期
-
@param format {@link SimpleDateFormat} todo-zhw DateTimeFormatter
-
@return 格式化后的字符串
-
@since 5.0.0
*/
public static String format(Date date, DateTimeFormatter format) {
if (null == format || null == date) {
return null;
}
Instant instant = date.toInstant();
ZoneId zoneId = ZoneId.systemDefault();
ZonedDateTime zonedDateTime = instant.atZone(zoneId);
LocalDateTime localDateTime = zonedDateTime.toLocalDateTime();
return format.format(localDateTime);
}
先把date类型转化为LocalDateTime类型,然后再进行DateTimeFormatter.format(LocalDateTime)的格式化
测试demo
//根据特定格式格式化日期
String str = “2021-07-25 20:11:25”;
DateTimeFormatter dtf = DateTimeFormatter.ofPattern(“yyyy-MM-dd HH:mm:dd”);
Date date = DateUtil.parse(str);
String dateStr = DateUtil.format(date,dtf);
System.out.println(dateStr);
Assert.assertEquals(str, dateStr);
修订版本 #5.7.5
/**
-
根据特定格式格式化日期
-
@param date 被格式化的日期
-
@param format {@link SimpleDateFormat} {@link DatePattern#NORM_DATETIME_FORMATTER}
-
@return 格式化后的字符串
-
@since 5.0.0
*/
public static String format(Date date, DateTimeFormatter format) {
if (null == format || null == date) {
return null;
}
// java.time.temporal.UnsupportedTemporalTypeException: Unsupported field: YearOfEra
// 出现以上报错时,表示Instant时间戳没有时区信息,赋予默认时区
return TemporalAccessorUtil.format(date.toInstant(), format);
}
更换了新的调用方法TemporalAccessorUtil.format(date.toInstant(), format),date.toInstant()返回Instant对象,则变成了TemporalAccessorUtil.format(Instant, format)
//TemporalAccessorUtil
/**
-
格式化日期时间为指定格式
-
@param time {@link TemporalAccessor}
-
@param formatter 日期格式化器,预定义的格式见:{@link DateTimeFormatter}
-
@return 格式化后的字符串
-
@since 5.3.10
*/
public static String format(TemporalAccessor time, DateTimeFormatter formatter) {
if (null == time) {
return null;
}
if(null == formatter){
formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
}
try {
return formatter.format(time);
} catch (UnsupportedTemporalTypeException e){
if(time instanceof LocalDate && e.getMessage().contains(“HourOfDay”)){
// 用户传入LocalDate,但是要求格式化带有时间部分,转换为LocalDateTime重试
return formatter.format(((LocalDate) time).atStartOfDay());
}else if(time instanceof LocalTime && e.getMessage().contains(“YearOfEra”)){
// 用户传入LocalTime,但是要求格式化带有日期部分,转换为LocalDateTime重试
return formatter.format(((LocalTime) time).atDate(LocalDate.now()));
} else if(time instanceof Instant){
// 时间戳没有时区信息,赋予默认时区
return formatter.format(((Instant) time).atZone(ZoneId.systemDefault()));
}
throw e;
}
}
对比了下跟5.6.5版本的差异,新增了当time是Instant时,给一个默认的时区
else if(time instanceof Instant){
// 时间戳没有时区信息,赋予默认时区
return formatter.format(((Instant) time).atZone(ZoneId.systemDefault()));
}
方法名称:DateUtil.formatDateTime(java.util.Date)
================================================================================================================
格式化日期时间
格式 yyyy-MM-dd HH:mm:ss
/**
-
格式化日期时间
-
格式 yyyy-MM-dd HH:mm:ss
-
@param date 被格式化的日期
-
@return 格式化后的日期
*/
public static String formatDateTime(Date date) {
if (null == date) {
return null;
}
return DatePattern.NORM_DATETIME_FORMAT.format(date);
}
首先好习惯,先对入参进行判空处理
然后调用DatePattern.NORM_DATETIME_FORMAT.format(date)返回FastDateFormat对象
针对只支持java8之前的程序,可以使用FastDateFormat线程安全替换SimpleDateFormat线程不安全–》源码分析
FastDateFormat 是一个线程安全的实现
来源 Apache Commons Lang 3.5
DatePattern.NORM_DATETIME_FORMAT–>
/**
- 标准日期时间格式,精确到秒 {@link FastDateFormat}:yyyy-MM-dd HH:mm:ss
*/
public static final FastDateFormat NORM_DATETIME_FORMAT = FastDateFormat.getInstance(NORM_DATETIME_PATTERN);
则转化为了FastDateFormat.format(date)
//FastDateFormat
@Override
public String format(final Date date) {
return printer.format(date);
}
//FastDatePrinter
@Override
public String format(final Date date) {
final Calendar c = Calendar.getInstance(timeZone, locale);
c.setTime(date);
return applyRulesToString©;
}
先把date转化为Calendar,方便获取日期和时间
private String applyRulesToString(final Calendar c) {
return applyRules(c, new StringBuilder(mMaxLengthEstimate)).toString();
}
private B applyRules(final Calendar calendar, final B buf) {
try {
for (final Rule rule : this.rules) {
rule.appendTo(buf, calendar);
}
} catch (final IOException e) {
throw new DateException(e);
}
return buf;
}
核心的代码是这块
for (final Rule rule : this.rules) {
rule.appendTo(buf, calendar);
}
测试demo
String dateStr = “2017-03-01”;
Date date = DateUtil.parse(dateStr);
String formatDateTime = DateUtil.formatDateTime(date);
Assert.assertEquals(“2017-03-01 00:00:00”, formatDateTime);
断点跟进代码:
往下跟代码
//FastDatePrinter
private static class PaddedNumberField implements NumberRule {
…
@Override
public void appendTo(final Appendable buffer, final Calendar calendar) throws IOException {
appendTo(buffer, calendar.get(mField));
}
/**
- {@inheritDoc}
*/
@Override
public final void appendTo(final Appendable buffer, final int value) throws IOException {
appendFullDigits(buffer, value, mSize);
}
…}
已经取到年份了:2017
往下跟代码:
//FastDatePrinter
private static class CharacterLiteral implements Rule {
…
@Override
public void appendTo(final Appendable buffer, final Calendar calendar) throws IOException {
buffer.append(mValue);
}
…
}
就是把’-'字符串直接拼接上去。
下一个获取月份:
//FastDatePrinter
private static class TwoDigitMonthField implements NumberRule {
…
/**
- {@inheritDoc}
*/
@Override
public void appendTo(final Appendable buffer, final Calendar calendar) throws IOException {
appendTo(buffer, calendar.get(Calendar.MONTH) + 1);
}
/**
- {@inheritDoc}
*/
@Override
public final void appendTo(final Appendable buffer, final int value) throws IOException {
appendDigits(buffer, value);
}
…
}
获取了月份:3
然后下一个:把’-'字符串直接拼接上去。
继续往下跟
//FastDatePrinter
private static class TwoDigitNumberField implements NumberRule {
…
@Override
public void appendTo(final Appendable buffer, final Calendar calendar) throws IOException {
appendTo(buffer, calendar.get(mField));
}
/**
- {@inheritDoc}
*/
@Override
public final void appendTo(final Appendable buffer, final int value) throws IOException {
if (value < 100) {
appendDigits(buffer, value);
} else {
appendFullDigits(buffer, value, 2);
}
}
…
}
这样获取到的日期:2017-03-01
然后加了一个空格字符串
时分秒的调用,都是调用一样的FastDatePrinter#TwoDigitNumberField。
//FastDatePrinter
private static class TwoDigitNumberField implements NumberRule {
…
@Override
public void appendTo(final Appendable buffer, final Calendar calendar) throws IOException {
appendTo(buffer, calendar.get(mField));
}
/**
- {@inheritDoc}
*/
@Override
public final void appendTo(final Appendable buffer, final int value) throws IOException {
if (value < 100) {
appendDigits(buffer, value);
} else {
appendFullDigits(buffer, value, 2);
}
}
…
}
这样就得到了"2017-03-01 00:00:00"
方法名称:DateUtil.formatDate(java.util.Date)
============================================================================================================
格式化日期部分(不包括时间)
格式 yyyy-MM-dd
/**
-
格式化日期部分(不包括时间)
-
格式 yyyy-MM-dd
-
@param date 被格式化的日期
-
@return 格式化后的字符串
*/
public static String formatDate(Date date) {
if (null == date) {
return null;
}
return DatePattern.NORM_DATE_FORMAT.format(date);
}
首先好习惯,先对入参进行判空处理
然后调用DatePattern.NORM_DATE_FORMAT.format(date)返回FastDateFormat对象
针对只支持java8之前的程序,可以使用FastDateFormat线程安全替换SimpleDateFormat线程不安全–》源码分析
FastDateFormat 是一个线程安全的实现
来源 Apache Commons Lang 3.5
/**
- 标准日期格式 {@link FastDateFormat}:yyyy-MM-dd
*/
public static final FastDateFormat NORM_DATE_FORMAT = FastDateFormat.getInstance(NORM_DATE_PATTERN);
则转化为了FastDateFormat.format(date),源码分析看上面
方法名称:DateUtil.formatTime(java.util.Date)
============================================================================================================
格式化时间
格式 HH:mm:ss
/**
-
格式化时间
-
格式 HH:mm:ss
-
@param date 被格式化的日期
-
@return 格式化后的字符串
-
@since 3.0.1
*/
public static String formatTime(Date date) {
if (null == date) {
return null;
}
return DatePattern.NORM_TIME_FORMAT.format(date);
}
首先好习惯,先对入参进行判空处理
然后调用DatePattern.NORM_TIME_FORMAT.format(date)返回FastDateFormat对象
针对只支持java8之前的程序,可以使用FastDateFormat线程安全替换SimpleDateFormat线程不安全–》源码分析
FastDateFormat 是一个线程安全的实现
来源 Apache Commons Lang 3.5
/**
- 标准时间格式 {@link FastDateFormat}:HH:mm:ss
*/
public static final FastDateFormat NORM_TIME_FORMAT = FastDateFormat.getInstance(NORM_TIME_PATTERN);
则转化为了FastDateFormat.format(date),源码分析看上面
方法名称:DateUtil.formatHttpDate(java.util.Date)
================================================================================================================
格式化为Http的标准日期格式
标准日期格式遵循RFC 1123规范,格式类似于:Fri, 31 Dec 1999 23:59:59 GMT
/**
-
格式化为Http的标准日期格式
-
标准日期格式遵循RFC 1123规范,格式类似于:Fri, 31 Dec 1999 23:59:59 GMT
-
@param date 被格式化的日期
-
@return HTTP标准形式日期字符串
*/
public static String formatHttpDate(Date date) {
if (null == date) {
return null;
}
return DatePattern.HTTP_DATETIME_FORMAT.format(date);
}
首先好习惯,先对入参进行判空处理
然后调用DatePattern.HTTP_DATETIME_FORMAT.format(date)返回FastDateFormat对象
针对只支持java8之前的程序,可以使用FastDateFormat线程安全替换SimpleDateFormat线程不安全–》源码分析
FastDateFormat 是一个线程安全的实现
来源 Apache Commons Lang 3.5
/**
- HTTP头中日期时间格式 {@link FastDateFormat}:EEE, dd MMM yyyy HH:mm:ss z
*/
public static final FastDateFormat HTTP_DATETIME_FORMAT = FastDateFormat.getInstance(HTTP_DATETIME_PATTERN, TimeZone.getTimeZone(“GMT”), Locale.US);
则转化为了FastDateFormat.format(date),源码分析看上面
方法名称:DateUtil.formatChineseDate(java.util.Date, boolean, boolean)
=====================================================================================================================================
格式化为中文日期格式,如果isUppercase为false,则返回类似:2018年10月24日,否则返回二〇一八年十月二十四日
/**
-
格式化为中文日期格式,如果isUppercase为false,则返回类似:2018年10月24日,否则返回二〇一八年十月二十四日
-
@param date 被格式化的日期
-
@param isUppercase 是否采用大写形式
-
@param withTime 是否包含时间部分
-
@return 中文日期字符串
-
@since 5.3.9
*/
public static String formatChineseDate(Date date, boolean isUppercase, boolean withTime) {
if (null == date) {
return null;
}
if (false == isUppercase) {
return (withTime ? DatePattern.CHINESE_DATE_TIME_FORMAT : DatePattern.CHINESE_DATE_FORMAT).format(date);
}
return CalendarUtil.formatChineseDate(CalendarUtil.calendar(date), withTime);
}
首先好习惯,先对入参进行判空处理
当不采用大写形式时
执行**(withTime ? DatePattern.CHINESE_DATE_TIME_FORMAT : DatePattern.CHINESE_DATE_FORMAT).format(date)**
这里用了一个多目运算,包含时间部分时,调用DatePattern.CHINESE_DATE_TIME_FORMAT .format(date), 不包含时间部分时,调用DatePattern.CHINESE_DATE_FORMAT.format(date)
/**
- 标准日期格式 {@link FastDateFormat}:yyyy年MM月dd日HH时mm分ss秒
*/
public static final FastDateFormat CHINESE_DATE_TIME_FORMAT = FastDateFormat.getInstance(CHINESE_DATE_TIME_PATTERN);
/**
- 标准日期格式 {@link FastDateFormat}:yyyy年MM月dd日
*/
public static final FastDateFormat CHINESE_DATE_FORMAT = FastDateFormat.getInstance(CHINESE_DATE_PATTERN);
由上面源码可知,两个都是返回FastDateFormat对象。
针对只支持java8之前的程序,可以使用FastDateFormat线程安全替换SimpleDateFormat线程不安全–》源码分析
FastDateFormat 是一个线程安全的实现
来源 Apache Commons Lang 3.5
/**
- HTTP头中日期时间格式 {@link FastDateFormat}:EEE, dd MMM yyyy HH:mm:ss z
*/
public static final FastDateFormat HTTP_DATETIME_FORMAT = FastDateFormat.getInstance(HTTP_DATETIME_PATTERN, TimeZone.getTimeZone(“GMT”), Locale.US);
则转化为了FastDateFormat.format(date),源码分析看上面
当采用大写形式时
执行CalendarUtil.formatChineseDate(CalendarUtil.calendar(date), withTime);
可以拆解成两部分:
-
CalendarUtil.calendar(date):把date对象转换为Calendar对象
-
CalendarUtil.formatChineseDate(Calendar calendar, boolean withTime):将指定Calendar时间格式化为纯中文形式,例如
2018-02-24 12:13:14转换为 二〇一八年二月二十四日(withTime为false)
2018-02-24 12:13:14 转换为 二〇一八年二月二十四日一十二时一十三分一十四秒(withTime为true)
CalendarUtil.calendar(date)源码分析:
/**
-
转换为Calendar对象
-
@param date 日期对象
-
@return Calendar对象
*/
public static Calendar calendar(Date date) {
if (date instanceof DateTime) {
return ((DateTime) date).toCalendar();
} else {
return calendar(date.getTime());
}
}
如果是hutool提供的DateTime类型,可以直接转化获取。
如果是date类型,则通过*cal.setTimeInMillis转化为Calendar对象。
/**
-
转换为Calendar对象
-
@param millis 时间戳
-
@return Calendar对象
*/
public static Calendar calendar(long millis) {
final Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(millis);
return cal;
}
有同学会发现,这个跟我们常用的Calendar.setTime(Date date),不一样,看了下源码
//Calendar
感受:
其实我投简历的时候,都不太敢投递阿里。因为在阿里一面前已经过了字节的三次面试,投阿里的简历一直没被捞,所以以为简历就挂了。
特别感谢一面的面试官捞了我,给了我机会,同时也认可我的努力和态度。对比我的面经和其他大佬的面经,自己真的是运气好。别人8成实力,我可能8成运气。所以对我而言,我要继续加倍努力,弥补自己技术上的不足,以及与科班大佬们基础上的差距。希望自己能继续保持学习的热情,继续努力走下去。
也祝愿各位同学,都能找到自己心动的offer。
分享我在这次面试前所做的准备(刷题复习资料以及一些大佬们的学习笔记和学习路线),都已经整理成了电子文档
例如
2018-02-24 12:13:14转换为 二〇一八年二月二十四日(withTime为false)
2018-02-24 12:13:14 转换为 二〇一八年二月二十四日一十二时一十三分一十四秒(withTime为true)
CalendarUtil.calendar(date)源码分析:
/**
-
转换为Calendar对象
-
@param date 日期对象
-
@return Calendar对象
*/
public static Calendar calendar(Date date) {
if (date instanceof DateTime) {
return ((DateTime) date).toCalendar();
} else {
return calendar(date.getTime());
}
}
如果是hutool提供的DateTime类型,可以直接转化获取。
如果是date类型,则通过*cal.setTimeInMillis转化为Calendar对象。
/**
-
转换为Calendar对象
-
@param millis 时间戳
-
@return Calendar对象
*/
public static Calendar calendar(long millis) {
final Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(millis);
return cal;
}
有同学会发现,这个跟我们常用的Calendar.setTime(Date date),不一样,看了下源码
//Calendar
感受:
其实我投简历的时候,都不太敢投递阿里。因为在阿里一面前已经过了字节的三次面试,投阿里的简历一直没被捞,所以以为简历就挂了。
特别感谢一面的面试官捞了我,给了我机会,同时也认可我的努力和态度。对比我的面经和其他大佬的面经,自己真的是运气好。别人8成实力,我可能8成运气。所以对我而言,我要继续加倍努力,弥补自己技术上的不足,以及与科班大佬们基础上的差距。希望自己能继续保持学习的热情,继续努力走下去。
也祝愿各位同学,都能找到自己心动的offer。
分享我在这次面试前所做的准备(刷题复习资料以及一些大佬们的学习笔记和学习路线),都已经整理成了电子文档
[外链图片转存中…(img-JDPlukdz-1715278256991)]