The crisis of 2020 has quietly passed

I don’t know if you remember

At the beginning of the year, the hashtag # reboot2020 was trending on Weibo

On the hardest days

Ordinary people need to watch less mobile phones and less news

Only then can we relieve our depression and fear

This year, some people didn’t make it

But many of them did

As we speak, the New Year has come to an end

It’s the New Year 2021…

No more feeling

Cough, want to know the New Year is safe?

Did “YYYY-MM-DD” send you New Year’s eggs?

The accident simulation

See the results of the above program, you will definitely have doubts, why is it different (inner whisper: “shouldn’t ah, there was no problem before”)

Accident analysis

SimpleDateFormat (SimpleDateFormat) is an online document that provides information about the date format

In Api, the definition of Y is year, which is easily understood as the meaning of year. Then the definition of Y is Week year, which represents the year of this Week. As long as this Week is New Year, this Week is counted as the next year, so the above accident scene appears.

In a foreign country, the week starts on Sunday and ends on Saturday. In fact, this problem has already occurred on December 27, 2020. The test code above is changed to 27, which will also change to December 27, 2021.

In the project, should try to avoid every conversion date manually writing format, here will inevitably produce such problem, a unified definition a DateUtil class, which offers a variety of ways of transformation format, and so commonly used to format the constants defined, so that New Year’s Easter eggs will replace, ha ha

public class DateUtil{
    /** * date format, year, for example: 2004,2008 */
    public static final String DATE_FORMAT_YYYY = "yyyy";
    /** * the date format is year and month, for example, 200707,200808 */
    public static final String DATE_FORMAT_YYYYMM = "yyyyMM";
    /** * Date format, year and month, for example: 200707, 2008-08 */
    public static final String DATE_FORMAT_YYYY_MM = "yyyy-MM";
    /** * date format, for example, 050630,080808 */
    public static final String DATE_FORMAT_YYMMDD = "yyMMdd";
    /** * Date format, year, month, day, separated by bars, for example: 06-12-25, 08-08-08 */
    public static final String DATE_FORMAT_YY_MM_DD = "yy-MM-dd";
    /** * date format, such as 20050630,20080808 */
    public static final String DATE_FORMAT_YYYYMMDD = "yyyyMMdd";
    /** * Date format, year month day, separated by a dash, for example: 2006-12-25, 2008-08-08 */
    public static final String DATE_FORMAT_YYYY_MM_DD = "yyyy-MM-dd";
    /** * Date format, such as 2016.10.05 */
    public static final String DATE_FORMAT_POINTYYYYMMDD = "yyyy.MM.dd";
    /** * Date format, for example, October 05, 2016 */
    public static finalString DATE_TIME_FORMAT_YYYY Year MM month DD day ="Yyyy year MM month DD day";
    /** * date format, for example, 200506301210,200808081210 */
    public static final String DATE_FORMAT_YYYYMMDDHHmm = "yyyyMMddHHmm";
    /** * Date format, such as 20001230 12:00, 20080808 20:08 */
    public static final String DATE_TIME_FORMAT_YYYYMMDD_HH_MI = "yyyyMMdd HH:mm";
    /** * Date format, for example: 2000-12-30 12:00, 2008-08-08 20:08 */
    public static final String DATE_TIME_FORMAT_YYYY_MM_DD_HH_MI = "yyyy-MM-dd HH:mm";
    /** * date format: year, month, day, hour, minute, second, for example, 20001230120000,20080808200808 */
    public static final String DATE_TIME_FORMAT_YYYYMMDDHHMISS = "yyyyMMddHHmmss";
    /** * Date format, year, month, day, hour, minute, second, month, day, day, day, day, day, day, day, day, day, day, day, day, day, day, day separated by a colon separated * example: 2005-05-10 23:20:00, 2008-08-08 20:08:08 */
    public static final String DATE_TIME_FORMAT_YYYY_MM_DD_HH_MI_SS = "yyyy-MM-dd HH:mm:ss";
    /** * The date format is year month day hour minute second millisecond, for example, 20001230120000123 20080808200808456 */
    public static final String DATE_TIME_FORMAT_YYYYMMDDHHMISSSSS = "yyyyMMddHHmmssSSS";
    /** * Date format, such as 10-05 12:00 */
    public static final String DATE_FORMAT_MMDDHHMI = "MM-dd HH:mm";
}
Copy the code

supplement

In addition,SimpleDateFormatThread is not safe, not recommended, when high concurrency, prone to problems, then how to solve?

  1. Using local variables

    public class DateUtil{
        public static  String formatDate(Date date)throws ParseException {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            return sdf.format(date);
        }
     
        public static Date parse(String strDate) throws ParseException {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            returnsdf.parse(strDate); }}Copy the code

    Create a new instance where SimpleDateFormat is needed. Whenever a thread-safe object is moved from being shared to being partially private, it avoids multithreading, but also increases the burden of creating the object. In general, the effect on performance is not significant.

  2. Add synchronization lock

    public class DateUtil {
        private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        public static  String formatDate(Date date)throws ParseException {
            synchronized (sdf){
                returnsdf.format(date); }}public static Date parse(String strDate) throws ParseException{
            synchronized (sdf){
                returnsdf.parse(strDate); }}}Copy the code

    In this way, when one thread is calling, other threads that want to call the method need to block, which will have a certain impact on performance when the number of concurrent threads is large.

  3. Using ThreadLocal

    public class DateUtil {
        private static ThreadLocal<DateFormat> sdfThreadLocal =  new ThreadLocal<DateFormat>(){
                @Override
                public SimpleDateFormat initialValue(a){
                   return  new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); }};public static  String formatDate(Date date)throws ParseException {
            return sdfThreadLocal.get().format(date);
        }
        public static Date parse(String strDate) throws ParseException{
            returnsdfThreadLocal.get().parse(strDate); }}Copy the code

    With ThreadLocal, you also make shared variables proprietary, and thread exclusivity can certainly reduce the overhead of creating objects in a concurrent environment compared to method exclusivity.

  4. Using DateTimeFormatter

    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
    // String to date
    LocalDate localDate = LocalDate.parse("The 2021-01-01 21:50:50",formatter);
    // Date to string
    LocalTime localTime = LocalTime.now();
    String strLocalTime = localTime.format(formatter);
    //yyyyMMdd
    String strLocalTime1 = localTime.format(DateTimeFormatter.BASIC_ISO_DATE); 
    Copy the code

    The code above is just an example, but there are many more handy ways to use DateTimeFormatter. It comes with some built-in formats that you don’t need to write yourself. Unlike SimpleDateFormat, DateTimeFormatter is not only immutable, it is thread-safe and can be used to create only one instance of DateTimeFormatter and reference it everywhere.

I wish you all the best in 2021 and an early end to the epidemic.

If you have any questions, please send me a private message. Let’s discuss and learn together