java.util.Calendar混淆
我在使用java.util.Calendar和commons lang DateUtil时遇到问题 问题是我的测试在本地机器上正常工作,在CloudBees上失败。似乎区域设置有问题,但我不确定 代码如下:java.util.Calendar混淆,java,internationalization,calendar,locale,cloudbees,Java,Internationalization,Calendar,Locale,Cloudbees,我在使用java.util.Calendar和commons lang DateUtil时遇到问题 问题是我的测试在本地机器上正常工作,在CloudBees上失败。似乎区域设置有问题,但我不确定 代码如下: import org.testng.Assert; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; //bla-bla-bla public static final Strin
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
//bla-bla-bla
public static final String TEST_DATE_AS_STRING = "13 10 2012 20:50:44";
public static final int MILLIS_IN_HOUR = 3600000;
private static final String LEAP_WEEK_DATE_AS_STRING = "31 10 2012 20:50:44";
private final SimpleDateFormat sdf = new SimpleDateFormat("dd MM yyyy HH:mm:ss");
@Test
public void getWeekDatePair() throws ParseException{
Date date = sdf.parse(TEST_DATE_AS_STRING);
DatePair dp = Util.DateTime.getWeekDatePair(date);
Assert.assertEquals(sdf.format(new Date(dp.getStart())), "08 10 2012 00:00:00");
//java.lang.AssertionError: expected [14 10 2012 00:00:00] but found [07 10 2012 00:00:00]
Assert.assertEquals(sdf.format(new Date(dp.getEnd())), "14 10 2012 00:00:00");
}
@Test
public void getLeapWeekDatePair() throws ParseException {
Date leapDate = sdf.parse(LEAP_WEEK_DATE_AS_STRING);
DatePair dp = Util.DateTime.getWeekDatePair(leapDate);
Assert.assertEquals(sdf.format(new Date(dp.getStart())), "29 10 2012 00:00:00");
//java.lang.AssertionError: expected [04 11 2012 00:00:00] but found [28 10 2012 00:00:00]
Assert.assertEquals(sdf.format(new Date(dp.getEnd())), "04 11 2012 00:00:00");
}
以下是失败的测试输出:
java.lang.AssertionError: expected [04 11 2012 00:00:00] but found [28 10 2012 00:00:00]
at org.testng.Assert.fail(Assert.java:94)
at org.testng.Assert.failNotEquals(Assert.java:494)
at org.testng.Assert.assertEquals(Assert.java:123)
at org.testng.Assert.assertEquals(Assert.java:176)
at org.testng.Assert.assertEquals(Assert.java:186)
at ru.rating.utils.UtilDateTimeTest.getLeapWeekDatePair(UtilDateTimeTest.java:77)
expected [14 10 2012 00:00:00] but found [07 10 2012 00:00:00]
Stacktrace
java.lang.AssertionError: expected [14 10 2012 00:00:00] but found [07 10 2012 00:00:00]
at org.testng.Assert.fail(Assert.java:94)
at org.testng.Assert.failNotEquals(Assert.java:494)
at org.testng.Assert.assertEquals(Assert.java:123)
at org.testng.Assert.assertEquals(Assert.java:176)
at org.testng.Assert.assertEquals(Assert.java:186)
at ru.rating.utils.UtilDateTimeTest.getWeekDatePair(UtilDateTimeTest.java:69)
以下是实施:
public static DatePair getWeekDatePair(){
return getWeekDatePair(new Date());
}
/**
* This is test method
* */
static DatePair getWeekDatePair( Date date){
Date truncDay = truncate(date.getTime(), Calendar.DAY_OF_MONTH);
Calendar calStart = getCalendarInstance(date, Calendar.DAY_OF_MONTH);
calStart.setTime(truncDay);
calStart.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
Calendar calEnd = Calendar.getInstance();
calEnd.setTime(calStart.getTime());
calEnd.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);
return new DatePair(calStart.getTime(), calEnd.getTime());
}
public static Date truncate(long date, int calField) {
Calendar cal = getCalendarInstance(new Date(date), calField);
cal = DateUtils.truncate(cal, calField);
return cal.getTime();
}
static Calendar getCalendarInstance(Date date, int calendarField){
//Calendar cal = Calendar.getInstance();
Calendar cal = new GregorianCalendar(Locale.ENGLISH);
cal.setTime(date);
if(calendarField!=Calendar.HOUR){
cal.set(Calendar.HOUR_OF_DAY, 0);
}
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
return cal;
}
虽然我们在这里缺少关键信息(如何实现
Util.DateTime.getWeekDatePair(java.Util.Date)
),但我怀疑您在那里做的是使用默认Locale
实例化java.Util.Calendar
,然后搜索每周的第一天
我的怀疑来自这样一个事实,即您没有将Locale实例传递给getWeekDatePair()
方法
现在,这里的问题是什么?嗯,一周的第一天取决于地点。因此,当您像这样实例化日历时:Calendar.getInstance()
,您实际上要做的是:Calendar.getInstance(Locale.getDefault(Locale.Category.FORMAT)
。当然,一周的第一天在两台不同的机器上可能不同,因为区域设置可能不同。例如,在美国,一周的第一天是星期天,但在波兰是星期一(我相信在俄罗斯也是这样,不是吗?),因此,如果你在两台不同的机器上做这个测试,第一台机器的Locale设置为en-US,第二台设置为ru-ru,你可能会得到不同的结果 如果这只是测试的问题,您也可以设置默认区域设置,一切都应该正常工作。但是,请记住,如果您正在测试web应用程序,使用默认区域设置是一件坏事,因为它将返回服务器区域设置,而不是来自web浏览器(或某些用户配置文件,如果您有)的区域设置。如果此区域设置不同,您可能会使用让最终用户感到困惑的内容
编辑 很明显,它是从实现中发生的,我给了你以前的提示。考虑这个代码:
Calendar cal = Calendar.getInstance(Locale.ENGLISH);
System.out.println(sdf.format(cal.getTime()));
// Cloning so that Calendar could be re-used
Calendar calEnd = (Calendar) cal.clone();
// Setting start of the week date
cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
System.out.println(sdf.format(cal.getTime()));
calEnd.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);
System.out.println(sdf.format(calEnd.getTime()));
此打印(正确):
13 10 2012 00:00:0008 10 2012 00:00:00
07 10 2012 00:00:00 现在,让我们将日历实例化更改为:
Calendar cal = Calendar.getInstance(Locale.forLanguageTag("ru-RU"));
瞧,现在你会看到:
13 10 2012 00:00:0008 10 2012 00:00:00
2012年10月14日00:00:00 为了了解为什么这是正确的行为,让我们也测试一下这段代码:
System.out.println(cal.getFirstDayOfWeek());
对于英语语言环境,它将返回1(星期日),而对于俄语语言环境,它将返回2(星期一)。该代码的行为正确,因为它从给定的星期返回星期一和星期日。唯一的“问题”是,该星期在世界各地都有其他含义
正如您所看到的,它与DateUtils无关,它只是与日历的行为相关事实上,行为应该是一致的,因此无论您在哪台机器上测试代码,您都应该得到一个错误。事实并非如此,我真的不明白为什么
根据您试图实现的目标,将Locale作为参数添加到方法中(并相应地实例化日历),然后编写一些覆盖几个Locale的测试(一些阿拉伯语的Locale可能也很有趣,因为没有人说一周的第一天必须是星期天或星期一)或只是修改测试日期,以便它们与正确的日历行为相匹配。尽管我们在这里缺少关键信息(如何实现
Util.DateTime.getWeekDatePair(java.Util.Date)
),我怀疑您在那里做的是使用默认的Locale
实例化java.util.Calendar
,然后搜索每周的第一天
我的怀疑来自这样一个事实,即您没有将Locale实例传递给getWeekDatePair()
方法
现在,这里的问题是什么?好的,一周的第一天取决于区域设置。因此,当您像这样实例化Calendar
:Calendar.getInstance()
,您实际上要做的是:Calendar.getInstance(Locale.getDefault(Locale.Category.FORMAT))
。当然,一周的第一天在两台不同的机器上可能会有所不同,因为地区可能不同。例如,在美国,一周的第一天是星期天,但在波兰是星期一(我相信在俄罗斯也是这样,不是吗?),因此,如果你在两台不同的机器上做这个测试,第一台机器的Locale设置为en-US,第二台设置为ru-ru,你可能会得到不同的结果 如果这只是测试的问题,您也可以设置默认区域设置,一切都应该正常工作。但是,请记住,如果您正在测试web应用程序,使用默认区域设置是一件坏事,因为它将返回服务器区域设置,而不是来自web浏览器(或某些用户配置文件,如果您有)的区域设置。如果此区域设置不同,您可能会使用让最终用户感到困惑的内容
编辑 很明显,它是从实现中发生的,我给了你以前的提示。考虑这个代码:
Calendar cal = Calendar.getInstance(Locale.ENGLISH);
System.out.println(sdf.format(cal.getTime()));
// Cloning so that Calendar could be re-used
Calendar calEnd = (Calendar) cal.clone();
// Setting start of the week date
cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
System.out.println(sdf.format(cal.getTime()));
calEnd.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);
System.out.println(sdf.format(calEnd.getTime()));
此打印(正确):
13 10 2012 00:00:0008 10 2012 00:00:00
07 10 2012 00:00:00 现在,让我们将日历实例化更改为:
Calendar cal = Calendar.getInstance(Locale.forLanguageTag("ru-RU"));
瞧,现在你会看到:
13 10 2012 00:00:0008 10 2012 00:00:00
2012年10月14日00:00:00 为了了解为什么这是正确的行为,让我们也测试一下这段代码:
System.out.println(cal.getFirstDayOfWeek());
对于英语语言环境,它将返回1(星期日),而对于俄语语言环境,它将返回2(星期一)。该代码的行为正确,因为它从给定的星期返回星期一和星期日。唯一的“问题”是,该星期在世界各地都有其他含义
正如您所看到的,它与DateUtils无关,它只是与日历的行为有关。并且由于这段代码:Calendar cal=new GregorianCalendar(Locale.ENGLISH);
该行为实际上应该是由