В канун Нового года вас вызывали на сверхурочную работу в формате "ГГГГ-ММ-дд"?

Java

Кризисный 2020 год прошел незаметно

Я не знаю, помнишь ли ты еще

В начале года на Weibo долгое время зависал горячий поиск #Restart2020#.

в самые трудные дни

Обычные люди должны меньше смотреть мобильные телефоны и меньше новостей

Для снятия внутренней депрессии и беспокойства

В этом году некоторые люди не несли его

Но в конце концов, больше людей спустилось

На данный момент у нас закончилась новогодняя ночь

Вот и наступил новый 2021 год...

Чувства не сказать

Кхм, интересно, безопасна ли новогодняя ночь?

"ГГГГ-ММ-дд" Новогодние яйца вам не прислали?

моделирование аварии

image-20210102205009226

Увидев результаты работы вышеуказанной программы, у всех обязательно возникнут сомнения, ведь Мао другой (шепчет про себя: "Нет, раньше проблем не было")

анализ аварий

Поскольку есть сомнения, давайте просмотрим Java Api, найдем документ в Интернете и найдемSimpleDateFormatВ нем есть описание формата даты, помогу найти:Онлайн-ссылка Java API

image-20210102210730768

Внутри АпиyИнтерпретацияyear, хорошо поняли смысл года, тоYИнтерпретацияWeek year, представляет год, в котором находится эта неделя, и поскольку эта неделя приходится на канун Нового года, то эта неделя засчитывается в следующий год, поэтому появилась показанная выше сцена аварии.

Неделя в чужой стране начинается в воскресенье и заканчивается в субботу, на самом деле эта проблема уже возникла 27 декабря 2020 г. Если приведенный выше тестовый код изменить на 27, он также станет 27 декабря 2021 г.

В проекте следует стараться не прописывать формат вручную каждый раз при конвертации даты, здесь неизбежно возникнут такие проблемы, и единое определениеDateUtilкласс, который предоставляет различные методы преобразования форматов и постоянные определения часто используемых форматов, так что пасхалки в Новом году будут заменены, ха-ха

public class DateUtil{
    /**
     * 日期格式,年份,例如:2004,2008
     */
    public static final String DATE_FORMAT_YYYY = "yyyy";
    /**
     * 日期格式,年份和月份,例如:200707,200808
     */
    public static final String DATE_FORMAT_YYYYMM = "yyyyMM";
    /**
     * 日期格式,年份和月份,例如:200707,2008-08
     */
    public static final String DATE_FORMAT_YYYY_MM = "yyyy-MM";
    /**
     * 日期格式,年月日,例如:050630,080808
     */
    public static final String DATE_FORMAT_YYMMDD = "yyMMdd";
    /**
     * 日期格式,年月日,用横杠分开,例如:06-12-25,08-08-08
     */
    public static final String DATE_FORMAT_YY_MM_DD = "yy-MM-dd";
    /**
     * 日期格式,年月日,例如:20050630,20080808
     */
    public static final String DATE_FORMAT_YYYYMMDD = "yyyyMMdd";
    /**
     * 日期格式,年月日,用横杠分开,例如:2006-12-25,2008-08-08
     */
    public static final String DATE_FORMAT_YYYY_MM_DD = "yyyy-MM-dd";
    /**
     * 日期格式,年月日,例如:2016.10.05
     */
    public static final String DATE_FORMAT_POINTYYYYMMDD = "yyyy.MM.dd";
    /**
     * 日期格式,年月日,例如:2016年10月05日
     */
    public static final String DATE_TIME_FORMAT_YYYY年MM月DD日 = "yyyy年MM月dd日";
    /**
     * 日期格式,年月日时分,例如:200506301210,200808081210
     */
    public static final String DATE_FORMAT_YYYYMMDDHHmm = "yyyyMMddHHmm";
    /**
     * 日期格式,年月日时分,例如:20001230 12:00,20080808 20:08
     */
    public static final String DATE_TIME_FORMAT_YYYYMMDD_HH_MI = "yyyyMMdd HH:mm";
    /**
     * 日期格式,年月日时分,例如: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";
    /**
     * 日期格式,年月日时分秒,例如:20001230120000,20080808200808
     */
    public static final String DATE_TIME_FORMAT_YYYYMMDDHHMISS = "yyyyMMddHHmmss";
    /**
     * 日期格式,年月日时分秒,年月日用横杠分开,时分秒用冒号分开
     * 例如: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";
    /**
     * 日期格式,年月日时分秒毫秒,例如:20001230120000123,20080808200808456
     */
    public static final String DATE_TIME_FORMAT_YYYYMMDDHHMISSSSS = "yyyyMMddHHmmssSSS";
    /**
     * 日期格式,月日时分,例如:10-05 12:00
     */
    public static final String DATE_FORMAT_MMDDHHMI = "MM-dd HH:mm";
}

Пополнить

Кроме того,SimpleDateFormatЭто не потокобезопасно и не рекомендуется.При высоком уровне параллелизма могут возникать проблемы.Как это решить?

  1. Как использовать локальные переменные

    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");
            return sdf.parse(strDate);
        }
    }
    

    использовать при необходимостиSimpleDateFormatСоздайте новый экземпляр в том месте, где можно избежать проблемы многопоточности всякий раз, когда объект с проблемой безопасности потоков изменяется с общего на локальный частный, но это также увеличивает нагрузку на создание объектов. В целом на производительность это особо не влияет.

  2. Плюс генлок

    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){
                return sdf.format(date);
            }
        }
        public static Date parse(String strDate) throws ParseException{
            synchronized (sdf){
                return sdf.parse(strDate);
            }
        }
    }
    

    Таким образом, когда поток вызывает, другие потоки, которые хотят вызвать этот метод, должны блокироваться, и когда многопоточный параллелизм велик, это будет иметь определенное влияние на производительность.

  3. использоватьThreadLocal

    public class DateUtil {
        private static ThreadLocal<DateFormat> sdfThreadLocal =  new ThreadLocal<DateFormat>(){
                @Override
                public SimpleDateFormat initialValue(){
                   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{
            return sdfThreadLocal.get().parse(strDate);
        }
    }
    

    использоватьThreadLocal, Это также превращает общие переменные в монопольное использование.Эксклюзивное использование потоков может определенно уменьшить накладные расходы на создание объектов в параллельной среде, чем монопольное использование методов.

  4. использоватьDateTimeFormatter

    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
    //字符串转日期
    LocalDate localDate = LocalDate.parse("2021-01-01 21:50:50",formatter);
    //日期转字符串
    LocalTime localTime = LocalTime.now();
    String strLocalTime = localTime.format(formatter);
    //yyyyMMdd
    String strLocalTime1 = localTime.format(DateTimeFormatter.BASIC_ISO_DATE); 
    

    Приведенный выше код является просто примером, оDateTimeFormatterЕсть также много удобных применений, он предоставляет несколько встроенных форматов, поэтому вам не нужно писать его самостоятельно. а такжеSimpleDateFormatразница в том,DateTimeFormatterЭто не только неизменяемый объект, но и потокобезопасный.DateTimeFormatterВы можете просто создать один экземпляр и ссылаться на него везде.

Желаю вам всего наилучшего в 2021 году и скорейшего окончания эпидемии!

Если у вас есть какие-либо вопросы, пожалуйста, обратите внимание на публичный аккаунт [Hugh's Whiteboard] Пишите мне в личку, обсуждайте и учитесь вместе