一个非常简单的 java 代码(获取工作日的日期),但是我得到的结果很奇怪,为什么?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3949242/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 04:05:46  来源:igfitidea点击:

A very simple java code (to get date of a week day), but Very Strange result I get, WHY?

javadatetime

提问by Mellon

I have the following java code to get the date of a specific week day:

我有以下 java 代码来获取特定工作日的日期:

SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
Calendar cal = Calendar.getInstance();
cal.setTime(new Date());
cal.set(Calendar.YEAR, 2010);
cal.set(Calendar.WEEK_OF_YEAR, 37); //week 37 of year 2010
cal.set(Calendar.DAY_OF_WEEK, Calendar.THURSDAY);
System.out.println("date="+sdf.format(cal.getTime()));

When I put this code in a main(String[] args)method, like the following:

当我将此代码放入main(String[] args)方法中时,如下所示:

import java.util.*;
import java.lang.*;
import java.text.SimpleDateFormat;

public class test{
    public static void main(String[] args){

    /** get dates from a known week ID **/
    SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
    Calendar cal = Calendar.getInstance();
    cal.setTime(new Date());
    cal.set(Calendar.YEAR, 2010);
    cal.set(Calendar.WEEK_OF_YEAR, 37);
    cal.set(Calendar.DAY_OF_WEEK, Calendar.THURSDAY);
    System.out.println("date="+sdf.format(cal.getTime()));
    }
}

and run it, I get the correct result which is date=09/09/2010. There is no problem.

并运行它,我得到正确的结果,即date=09/09/2010. 没有问题。

HOWEVER...

然而...

When I put this code in a function of a Class, like the following:

当我将此代码放在类的函数中时,如下所示:

Public Class MyService{

  MyService(){}
  ...
  ...
  public String getDateOfWeekDay(int weekId, int year, int weekDay){
      //weekId = 37; year=2010; weekDay = Calendar.THURSDAY

      SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
      Calendar cal = Calendar.getInstance();
      cal.setTime(new Date());
      cal.set(Calendar.YEAR, year);
      cal.set(Calendar.WEEK_OF_YEAR, weekId);
      cal.set(Calendar.DAY_OF_WEEK, weekDay);

      //I am developing android app. so I use Log to printout
      logPrinter.println("date="+sdf.format(cal.getTime())); 

      return  sdf.format(cal.getTime());    
  }

}

in another class MainClass, MainClass will invoke this service function like following:

在另一个类 MainClass 中,MainClass 将调用此服务函数,如下所示:

Public Class MainClass{

MyService myService = new MyService();
myService.getDateOfWeekDay(37,2010,Calendar.THURSDAY);

}

But the result returned is always the date of the current week's thursday (date=14/10/2010), not the Thursday of the week which I specified (week 37, year 2010, Thursday). WHY???? I use exactly the same java code to get the date of the specific week day, only used it in different ways, why the result is different???? I can not understand this...Anybody can explain to me??

但返回的结果始终是当周的星期四 (date=14/10/2010) 的日期,而不是我指定的那一周的星期四(2010 年第 37 周,星期四)。为什么????我使用完全相同的java代码获取特定工作日的日期,只是使用方式不同,为什么结果不同????我无法理解这一点……谁能给我解释一下??

回答by duffymo

Yes, JodaTime is wonderful, but I'll bet you'd rather know what's wrong with your stuff.

是的,JodaTime 很棒,但我敢打赌你更想知道你的东西有什么问题。

Adding another JAR dependency might be a problem for a mobile device.

添加另一个 JAR 依赖项对于移动设备来说可能是个问题。

That method isn't good, IMO. The name is a misnomer, and it's doing too many things. You're creating a String, not a Date, and you're printing to a log. I'd recommend returning a Date and let clients worry about whether they want to turn it into a String. Logging is a cross-cutting concern.

那个方法不好,IMO。这个名字用词不当,它做的事情太多了。您正在创建一个字符串,而不是一个日期,并且您正在打印到日志。我建议返回一个 Date 并让客户担心他们是否要将其转换为 String。日志记录是一个跨领域的问题。

Here's a class (and a JUnit test) that works. See what's different:

这是一个有效的类(和一个 JUnit 测试)。看看有什么不同:

package util;

import java.util.Calendar;
import java.util.Date;

public class DateUtils
{
    public static Date getDateOfWeekDay(int weekId, int year, int weekDay)
    {
        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.YEAR, year);
        cal.set(Calendar.WEEK_OF_YEAR, weekId);
        cal.set(Calendar.DAY_OF_WEEK, weekDay);
        cal.set(Calendar.HOUR, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);

        return cal.getTime();
    }

}

JUnit test:

JUnit 测试:

package util;

import org.junit.Assert;
import org.junit.Test;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

/**
 * DateUtilsTest
 * User: Michael
 * Date: 10/16/10
 * Time: 10:40 AM
 */
public class DateUtilsTest
{
    public static final DateFormat DEFAULT_FORMAT = new SimpleDateFormat("dd/MM/yyyy");

    @Test
    public void testNewYearsDayLastYear() throws ParseException
    {
        Date expected = DEFAULT_FORMAT.parse("1/1/2009");
        Date actual = DateUtils.getDateOfWeekDay(1, 2009, Calendar.THURSDAY);

        Assert.assertEquals(expected, actual);
    }

    @Test
    public void testTaxDay() throws ParseException
    {
        Date expected = DEFAULT_FORMAT.parse("15/4/2010");
        Date actual = DateUtils.getDateOfWeekDay(16, 2010, Calendar.THURSDAY);

        Assert.assertEquals(expected, actual);
    }

    @Test
    public void testGetDateOfWeekDay() throws ParseException
    {
        Date expected = DEFAULT_FORMAT.parse("16/10/2010");
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(expected);
        int week = calendar.get(Calendar.WEEK_OF_YEAR);
        int year = calendar.get(Calendar.YEAR);
        int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);

        Date actual = DateUtils.getDateOfWeekDay(week, year, dayOfWeek);

        Assert.assertEquals(expected, actual);
    }
}

回答by andersoj

It's becoming a rote answer around here, but: Use JodaTimeor one of the alternatives. Investing precious cycles into understanding the JDK calendar API is throwing good money after bad.

它在这里成为一个死记硬背的答案,但是:使用JodaTime或其中一种替代方法。在理解 JDK 日历 API 上投入宝贵的周期是在赔钱。

Related on SO: Should I use native date/time; I see (now) you're doing Android development, which I can't speak to, but on SO: JodaTime on Android?

与 SO 相关:我是否应该使用本机日期/时间;我看到(现在)你正在做 Android 开发,我不能说,但是在 SO:Android上的JodaTime?

If you're insisting on JDK, I did try your code, with a slight modification. First, I'd eliminate the cal.setTime(new Date())-- it's not doing anything, and it's confusing since it might (seem to) correlate to always getting a date around "now," since new Date()gives you now. However, in your code, it still should be overridden by the following setX calls.

如果您坚持使用 JDK,我确实尝试了您的代码,并稍作修改。首先,我会消除cal.setTime(new Date())- 它没有做任何事情,并且令人困惑,因为它可能(似乎)与总是在“现在”附近约会,因为new Date()现在给了你。但是,在您的代码中,它仍应被以下 setX 调用覆盖。

class DateTest
{
    DateTest(){}

    public String getDateOfWeekDay(int weekId, int year, int weekDay){

        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.YEAR, year);
        cal.set(Calendar.WEEK_OF_YEAR, weekId);
        cal.set(Calendar.DAY_OF_WEEK, weekDay);

        SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
        System.out.println("date="+sdf.format(cal.getTime())); 

        return  sdf.format(cal.getTime());    
    }

    public static void main(String args[])
    {
      DateTest dt = new DateTest();
      for (int weekCount = 1; weekCount <= 53; weekCount++) {
        dt.getDateOfWeekDay(weekCount,2010,Calendar.THURSDAY);
      }
    }

}

And I get exactly what I expect:

我得到了我所期望的:

date=31/12/2009 
date=07/01/2010 
...
date=23/12/2010 
date=30/12/2010

Do you see different?

你看不一样?

回答by RedGrittyBrick

public class CalendarTest {

    public static String getDateOfWeekDay(int weekId, int year, int weekDay) {
        SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
        Calendar cal = Calendar.getInstance();
        cal.setTime(new Date());
        cal.set(Calendar.YEAR, year);
        cal.set(Calendar.WEEK_OF_YEAR, weekId);
        cal.set(Calendar.DAY_OF_WEEK, weekDay);
        return sdf.format(cal.getTime());
    }

    public static void main(String[] args) {
        String someDay = getDateOfWeekDay(37,2010,Calendar.THURSDAY);
        System.out.println(someDay);
    }

}

Outputs 16/09/2010 As does

产出 16/09/2010 一样

public class CalendarTest {
    public static void main(String[] args) {
        MyService s = new MyService();
        String someDay = s.getDateOfWeekDay(37, 2010, Calendar.THURSDAY);
        System.out.println(someDay);
    }
}

class MyService {
    public String getDateOfWeekDay(int weekId, int year, int weekDay) {
        SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
        Calendar cal = Calendar.getInstance();
        cal.setTime(new Date());
        cal.set(Calendar.YEAR, year);
        cal.set(Calendar.WEEK_OF_YEAR, weekId);
        cal.set(Calendar.DAY_OF_WEEK, weekDay);
        return sdf.format(cal.getTime());
    }
}

回答by soc

Well, because these answers are less about answering your actual question than recommending to use JodaTime, I'll throw in my recommendation againstJodaTime.

好吧,因为这些答案与其说是回答您的实际问题,不如说是建议使用 JodaTime,所以我将提出反对JodaTime 的建议。

Date/Calendar as well as JodaTime have significant design flaws (quoting the authors) and if you plan to do work with time and date, use JSR-310.

Date/Calendar 和 JodaTime 都有明显的设计缺陷(引用作者的话),如果您打算使用时间和日期,请使用JSR-310

JSR-310 is the replacement for both Date/Calendar and JodaTime which is more consistent and works better than both. There are considerations to include JSR-310 in Java 7.

JSR-310 是 Date/Calendar 和 JodaTime 的替代品,它比两者更一致且效果更好。在 Java 7 中包含JSR-310需要考虑。

Regardless if that works out or not, it is possible to use it today. It is just a jar file like JodaTime.

不管这是否有效,今天都可以使用它。它只是一个类似于 JodaTime 的 jar 文件。

The benefits are:

好处是:

  • Fixes the remaining problems of JodaTime
  • Consistent library design
  • Better naming conventions
  • Easier to read API
  • Everything immutable
  • Better usability from other programming languages
  • 修复 JodaTime 剩余问题
  • 一致的库设计
  • 更好的命名约定
  • 更易于阅读的 API
  • 一切不变
  • 来自其他编程语言的更好的可用性

If you are interested in this topic:

如果您对此主题感兴趣: