一个非常简单的 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
A very simple java code (to get date of a week day), but Very Strange result I get, WHY?
提问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:
如果您对此主题感兴趣:
- Video about JSR-310.
- Slightly related answerabout the design decisions of Date/Time APIs in different languages.
- 关于 JSR-310 的视频。
- 关于不同语言的日期/时间 API 的设计决策的稍微相关的答案。