本地与服务器执行结果不同的一种情况——格式化日期未设定区域

在德不在鼎。….. 德之休明,虽小,重也;其奸回昏乱,虽大,轻也。鼎之轻重,未可问也。

起源:本地100,线上200

最近生产环境除了一个奇怪的事情:我司程序员张三在其本地调试运行某个功能模块的代码后,上线运行通过,但是发现其执行结果与预期不符合,而且,最最诡异的事情是,在其本地执行与预期结果是相符合的。

简单来说,一段程序在张三的电脑上运行,执行结果为100。将同样的一段代码放在服务器上执行,执行结果就变成200了。

定位:打log

为了找到问题,我们在代码各个IF判断位置插入日志,重新部署在服务器上执行,然后根据日志判断其程序走向与定位问题。

结果

最终,我们定位到这样一个方法:

1
2
3
4
5
6
7
8
9
/**
* 星期几
* @param date
* @return 星期几
*/
public static String getChineseWeek(Date date) {
SimpleDateFormat EEEE = new SimpleDateFormat("EEEE");
return EEEE.format(date);
}

首先我们在本地运行一下这段代码,编写测试用例:

1
2
3
4
5
@Test
public void testSimpleDateFormate() {
SimpleDateFormat EEEE = new SimpleDateFormat("EEEE");
System.out.println(EEEE.format(new Date()));
}

执行结果如下:

1
星期四

但是我们在服务器中,同样的代码,执行结果却不同,如下所示:

1
[INFO]-[Thread: catalina-exec-7699]-[com.jfinal.kit.LogKit.info()]: Thursday

经过查询发现,原来SimpleDateFormat是和其运行环境有关的。其完整文档如下:

1
>public SimpleDateFormat(String pattern)

使用给定模式SimpleDateFormat并使用默认的FORMAT语言环境的默认日期格式符号。 注意:此构造函数可能不支持所有区域设置。 要全面覆盖,请使用DateFormat类中的工厂方法。

这相当于调用SimpleDateFormat(pattern, Locale.getDefault(Locale.Category.FORMAT))

  • 参数

pattern - 描述日期和时间格式的模式

  • 异常

NullPointerException - 如果给定的模式为空

IllegalArgumentException - 如果给定的模式无效

  • 另请参见:

Locale.getDefault(java.util.Locale.Category)Locale.Category.FORMAT

我们通常使用的格式:yyyy-MM-dd不论在中文环境下还是英文环境下输出都是一样的,而遇到星期这种表达,中文与英文出现了分期,那么,如何才能避免这种的表达形式的,那就是指明所使用的语言。

如下所示:

1
2
3
4
5
6
7
8
9
/**
* 星期几
* @param date
* @return 星期几
*/
public static String getChineseWeek(Date date) {
SimpleDateFormat EEEE = new SimpleDateFormat("EEEE", Locale.CHINESE);
return EEEE.format(date);
}

如此便不会出现因为服务器区域设定不同而造成的格式不达预期的问题。

设定区域方法的完整官方文档如下:

1
2
public SimpleDateFormat(String pattern,
Locale locale)

构造一个SimpleDateFormat使用给定的模式和给定的区域设置的默认日期格式符号。 注意:此构造函数可能不支持所有区域设置。 为了全面覆盖,请使用DateFormat类中的工厂方法。

  • 参数

    pattern - 描述日期和时间格式的模式

    locale - 应使用日期格式符号的区域设置

  • 异常

    NullPointerException - 如果给定的模式或区域设置为空

    IllegalArgumentException - 如果给定的模式无效