Java SimpleDataFormat返回的日期带有前导零,如0022 2018年2月

Java SimpleDataFormat返回的日期带有前导零,如0022 2018年2月,java,android,date,simpledateformat,date-formatting,Java,Android,Date,Simpledateformat,Date Formatting,这是我的SimpleDataFormat实例: public static final SimpleDateFormat DD_MMM_YYYY = new SimpleDateFormat("dd MMM yyyy"); 我正在将以毫秒为单位的时间戳转换为这种日期格式 有时它会返回正确的日期,如: 2018年2月22日 但有时在极少数情况下,它会返回错误的日期,如: 0022 2018年2月 为什么要加两个前导零 我的方法如下- public static S

这是我的SimpleDataFormat实例:

public static final SimpleDateFormat DD_MMM_YYYY =
                new SimpleDateFormat("dd MMM yyyy");
我正在将以毫秒为单位的时间戳转换为这种日期格式

有时它会返回正确的日期,如:

2018年2月22日

但有时在极少数情况下,它会返回错误的日期,如:

0022 2018年2月

为什么要加两个前导零

我的方法如下-

public static String convertLongToDate(long timestamp) {
        Calendar calendar = Calendar.getInstance(TimeZone.getDefault());
        long todaysTimestamp = calendar.getTimeInMillis();
        calendar.add(Calendar.DAY_OF_YEAR, -1);
        long yesterdayTimestamp = calendar.getTimeInMillis();
        calendar.setTimeInMillis(timestamp);
        String timeString;

        String todaysDateStr = DD_MMM_YYYY.format(todaysTimestamp);
        String givenDateStr = DD_MMM_YYYY.format(calendar.getTimeInMillis());

        Log.d("Check", "date-> todaysDateStr=" + todaysDateStr + ", givenDateStr=" + givenDateStr+", todayLength="+todaysDateStr.length()+", givenLength="+givenDateStr.length());
        if (todaysDateStr.equalsIgnoreCase(givenDateStr)) {
            timeString = AppConstants.TODAY;
        } else if (DD_MMM_YYYY.format(yesterdayTimestamp).equalsIgnoreCase(givenDateStr)) {
            timeString = AppConstants.YESTERDAY;
        } else {
            timeString = givenDateStr;
        }
        timeString = timeString.trim();
        return timeString;
    }

如果没有关于如何使用格式化程序的更多信息,很难判断问题出在哪里

但我猜这是因为SimpleDataFormat不是线程安全的

在多线程环境中运行时,奇怪的事情开始发生。只要访问谷歌,你就会发现很多关于这方面的文章:

更新: 使用您的代码,我无法重现这个问题,但我仍然认为它与在多线程环境中使用非线程安全类有关——这是我所知道的唯一可能发生类似问题的情况,特别是有时的因素

愚蠢的问题:是否有任何AppConstants值具有前导零?只是问问,谁知道

选择 为此,您可以使用更好的API,例如ThreeTen Backport:

这样,您的代码变得更加清晰,易于理解/维护:

public static String convertLongToDate(long timestamp) {
    DateTimeFormatter f = DateTimeFormatter.ofPattern("dd MMM yyyy");
    ZonedDateTime today = ZonedDateTime.now(ZoneId.systemDefault());
    ZonedDateTime yesterday = today.minusDays(1);

    ZonedDateTime givenDate = Instant.ofEpochMilli(timestamp).atZone(ZoneId.systemDefault());

    String timeString;
    // compare just the date (day, month, year)
    // no need to convert to string to compare if dates are the same
    if (today.toLocalDate().equals(givenDate.toLocalDate())) {
        timeString = AppConstants.TODAY;
    } else if (yesterday.toLocalDate().equals(givenDate.toLocalDate())) {
        timeString = AppConstants.YESTERDAY;
    } else {
        timeString = givenDate.format(f);
    }
    timeString = timeString.trim();
    return timeString;
}
这个API是线程安全的,SimpleDataFormat有时会发生的奇怪事情在这里不会发生


或者,如果您不想使用其他API,您可以使用本文的解决方案:

如果您显示当前日期和特定格式,然后在代码下面使用

Date c = Calendar.getInstance().getTime(); // get current date and time.
    System.out.println("Current time => " + c);

    SimpleDateFormat df = new SimpleDateFormat("dd MMM yyyy"); // define your format.
    String formattedDate = df.format(c);
    System.out.println("New Date To Show::"+formattedDate);

永远不会发生所以我想这是你的错你说的有时候是什么意思?同样的代码运行1000次,有几次只运行前导零?有没有修改中间的值?没有什么是修改值,有一个函数以毫秒为单位获取时间戳并将其转换为给定的格式。您能展示一些生成此值的代码吗?这个问题现在没有意义了,因为可怕的日历和SimpleDateformat类已被java.time类取代。大部分java.time功能都在项目中向后移植到Java6和Java7。进一步适应项目中早期的Android。看,我也在做同样的事情。请检查我的代码,我已更新我的问题。AppConstants没有任何零。问题可能是线程安全。将实现您的代码并让您知道。+1。在Android上使用Three-Ten Backport的代码不仅更清晰易读,而且非常重要的是,它是线程安全的,因为现代类是。使用LocalDate everywhere可以使它变得更简单,唯一需要一个ZonedDateTime的地方是转换长时间戳,因此只需立即转换为LocalDate即可。@MohitRajput您也可以将解决方案与ThreadLocal一起使用,正如这里所解释的:DateTimeFormatter是线程安全的,您可以安全地让它作为问题中的格式化程序成为公共静态final。