0

我在使用 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 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;
}
4

1 回答 1

4

尽管我们在这里缺少关键信息(如何Util.DateTime.getWeekDatePair(java.util.Date)实现),但我怀疑您在那里所做的事情是java.util.Calendar使用默认值进行实例化Locale,然后搜索一周的第一天。

我的怀疑来自这样一个事实,即您没有将 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:00
08 10 2012 00:00:00
07 10 2012 00:00:00

现在,让我们将日历实例更改为:

Calendar cal = Calendar.getInstance(Locale.forLanguageTag("ru-RU"));

瞧,现在你会看到:

13 10 2012 00:00:00
08 10 2012 00:00:00
14 10 2012 00:00:00

要了解为什么这是正确的行为,让我们也测试一下这段代码:

System.out.println(cal.getFirstDayOfWeek());

对于英语语言环境,它将返回 1(星期日),而不是 2(星期一),这是俄语语言环境的结果。此代码行为正确,因为它返回给定周的星期一和星期日。唯一的“问题”是这样一个事实,那一周在世界各地都意味着其他事情。

如您所见,它与 DateUtils 无关,它仅与 Calendar 的行为有关。由于这段代码:Calendar cal = new GregorianCalendar(Locale.ENGLISH);行为实际上应该是一致的,所以无论你在什么机器上测试代码,你都应该总是得到一个错误。不是这样的,我真的不明白为什么。

根据您要实现的目标,将 Locale 作为参数添加到您的方法(并相应地实例化 Calendar)可能是有意义的,然后编写一些涵盖少数 Locale 的测试(一些阿拉伯语 Locale 也可能很有趣,因为没有人说第一天周必须是星期日或星期一)仅修改测试日期以使其与正确的日历行为相匹配。

于 2012-12-15T20:41:20.437 回答