任意分配Java.Util.Calendar值

任意分配Java.Util.Calendar值,java,java-7,java.util.calendar,Java,Java 7,Java.util.calendar,我目前正与Java.Util.Calendar 我有一个方法,可以创建一个日历,其中包含年、月和日的随机值 public Calendar getRandomGeburtstag() { int year = 1999 - (int) (Math.random() * 80); int month = (int) (Math.random() * 12) + 1; int monthLength = 28; int day = (i

我目前正与
Java.Util.Calendar

我有一个方法,可以创建一个日历,其中包含年、月和日的随机值

public Calendar getRandomGeburtstag() {
        int year = 1999 - (int) (Math.random() * 80);
        int month = (int) (Math.random() * 12) + 1;
        int monthLength = 28;
        int day = (int) (Math.random() * monthLength) + 1;      
        Calendar calendar = Calendar.getInstance();
        calendar.clear();
        calendar.set(year, month, day);
        return calendar;
} 
我将此日历存储在“Person”类中,该类具有简单的getter方法。
然后我要求在两个不同的场合使用日历。 在此期间,对象不会被更改。 打印日历会提供两种不同的输出:

java.util.GregorianCalendar[areAllFieldsSet=false,ERA=?,WEEK_OF_YEAR=?,WEEK_OF_MONTH=?,DAY_OF_YEAR=?,DAY_OF_WEEK=?,DAY_OF_WEEK_IN_MONTH=?,AM_PM=?,HOUR=?,HOUR_OF_DAY=?,MINUTE=?,SECOND=?,MILLISECOND=?,ZONE_OFFSET=?,DST_OFFSET=?]  

(我省略了保持不变的字段,它们都在两个打印输出中设置)
如您所见,以前未设置的所有字段都在两个请求之间的某个位置获得了默认值或计算值。 在请求之间不使用objected,因此它可能是JVM。
问题是,
ZONE\u OFFSET
字段被我无权访问的方法使用。仅当给出了
区域偏移=?
时,才会打印所需的输出。

有什么方法可以停止这些值的自动分配吗?

这可能不是您想要的答案,但是使用
java.time
包编写会容易得多

public LocalDate getRandomGeburtstag() {
  LocalDate min = LocalDate.of(1919, 1, 1);
  LocalDate max = LocalDate.of(1999, 12, 31);
  long diff = max.toEpochDay() - min.toEpochDay();
  return LocalDate.ofEpochDay(min.toEpochDay() + (long) (Math.random() * diff));
} 

您当前的方法不会生成所有可能的日期,例如29、30、31。我假设这是一个解决方法,但在操作epoch millis时不需要它。

也许您可以在以下答案中找到有关
日历的奇异行为的更多信息:

基本上,当您调用
set
时,不会自动重新计算所有这些内部字段,并且内部重新计算是任意的,您无法控制何时完成以及重新计算哪些字段

最好的替代方法是使用注释中建议的Three-Ten Backport,这样您就可以使用
LocalDate
和java.time API的所有其他功能,而java.time API没有这么多的
Calendar

但是如果您坚持使用旧API,那么有一个(丑陋的)替代方案:

SimpleDateFormat sdf = new SimpleDateFormat("d-M-yyyy");
Date date = sdf.parse(day + "-" + month + "-" + year);

Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
日期
将时间字段设置为零,
日历
将设置所有字段(打印时无


只是提醒一下,上面的月份值是从1到12,而在
calendar.set
方法中,接受的值是从0到11(这个糟糕的API的另一个恼人行为)。

由于我正在处理的项目还没有转换成java 8,我很遗憾不能使用
java。时间
(会让很多事情变得更简单)。大约2月30日:目前的方法将
天的范围限制在1-28天。显然,Java8解决了这个限制。我将更新标记和变量名以澄清问题。实际上,您可以在Java6和Java7中使用java.time。添加到你的项目中,(1)你可以使用相同的功能,(2)你是未来的证明。如果您的旧代码需要
Calendar
对象,请使用。我会在
Calendar.internalSet(int,int)
方法中设置断点时尝试调试您的代码,以查看对象的更改位置。JVM不太可能更改您的对象,因为
Calendar
不是单例。一种解决方法是使用不可变类型,但
LocalDate
仅在8+中可用。对于Java 6和7,可通过使用
LocalDate
来获得@卡罗多贝基:我同意你的建议。所以这件事发生了相当尴尬的转变。我根据@KarolDowbecki的建议调试了代码。事实证明,我只是不知道我的遗留代码实际上做了什么。在某种程度上(出于不可理解的原因),它实际上改变了我向它发送的日历。在我想到它会在克隆中做所有的改变之前。给遗留代码一个克隆解决了这个问题。现在我真的不知道如何处理这个问题。问题本身现在是无效的(因为所描述的问题最初并不存在),但答案仍然有效。Stackoverflow告诉我不要删除问题,这样其他人就可以使用提供的信息。但是我不确定这个问题是否有帮助。你是对的,你应该把问题留在这里,这样其他读者可以从答案中受益。很好,你解决了。
SimpleDateFormat sdf = new SimpleDateFormat("d-M-yyyy");
Date date = sdf.parse(day + "-" + month + "-" + year);

Calendar calendar = Calendar.getInstance();
calendar.setTime(date);