Григорианский календарь Java возвращает неправильный месяц

Итак, я занимаюсь этим уже несколько часов, и он возвращает правильный год и день, но по какой-то странной причине возвращает неправильный месяц. Я уверен, что это простое решение, но я не могу понять это.

package gregoriancalendar;

import java.util.GregorianCalendar;

public class Calendar8_5 {



public static void main(String[] args){

GregorianCalendar calendar = new GregorianCalendar();
System.out.println("Current Year, Month & Date: ");
System.out.println("Year is " + calendar.get(1));
System.out.println("Month is " + calendar.get(2));
System.out.println("Day is " + calendar.get(5));


calendar.setTimeInMillis(1234567898765L);
//Elapse Time
System.out.println("Set Value of 1234567898765L");
System.out.println("Year is " + calendar.get(1));
System.out.println("Month is " + calendar.get(2));
System.out.println("Day is " + calendar.get(5));
   }
  }

person Kupcake69    schedule 04.12.2013    source источник
comment
Вы читали javadoc?   -  person Sotirios Delimanolis    schedule 04.12.2013
comment
Наверное из-за этого? stackoverflow.com/ вопросы/344380/   -  person Rob    schedule 04.12.2013
comment
Хорошо, это имеет больше смысла, так что календарь 0-11 11 декабря. Здравый смысл подсказал бы мне добавить 1, но я знаю, что это не сработает и даст странный результат. Так есть ли работа вокруг этого?   -  person Kupcake69    schedule 04.12.2013
comment
Почему бы не добавить 1?   -  person JB Nizet    schedule 04.12.2013
comment
Добавление одного приводит к 111 или 49   -  person Kupcake69    schedule 04.12.2013
comment
@Kupcake69 Что вы имели в виду под //Elapse Time?   -  person Basil Bourque    schedule 04.12.2013
comment
Дубликат: Календарь возвращает неверный месяц   -  person Basil Bourque    schedule 12.08.2016
comment
Дубликат: Создание объекта даты Java из года, месяца, дня   -  person Basil Bourque    schedule 30.08.2016


Ответы (3)


tl;dr

Чтобы получить число 1-12 для текущего месяца:

LocalDate.now()
         .getMonthValue()

Лучше указать желаемый/ожидаемый часовой пояс.

LocalDate.now( 
    ZoneId.of( "America/Montreal" ) 
).getMonthValue()

Аналогичным образом вызовите .getYear() и .getDayOfMonth().

Подробности

он возвращает неправильный месяц

Как говорили другие, в Calendar месяцы с января по декабрь имеют сумасшедшие номера 0-11, а не 1-12. Одно из многих неудачных дизайнерских решений в старых классах даты и времени. Эти классы теперь унаследованы и заменены классами java.time.

Так есть ли работа вокруг этого?

Да, есть обходной путь. Используйте хорошую библиотеку даты и времени, а не беспорядок, который представляет собой java.util.Date/Calendar. Современный способ - с классами java.time.

Текущий момент

Часовой пояс имеет решающее значение для получения текущей даты и времени. В любой данный момент дата и время настенных часов зависят от зоны.

ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = ZonedDateTime.now( z );

Вы можете запрашивать различные компоненты, такие как год, номер месяца, локализованное название месяца, через Month и день месяца.

System.out.println ( "Current: " + zdt );
System.out.println( "Year is " + zdt.getYear() );
System.out.println( "Month is " + zdt.getMonthValue() );
System.out.println( "Month name is " + zdt.getMonth().getDisplayName( TextStyle.FULL , Locale.CANADA_FRENCH ) );  // Or Locale.US, Locale.ITALY, etc.
System.out.println( "Day is " + zdt.getDayOfMonth() );

Текущий: 2016-12-14T04:54:44.802-05:00[Америка/Монреаль]

Год 2016

Месяц 12

Название месяца декабрь

День 14

См. действующий код на IdeOne.com.

Если вас интересует только дата, а не время суток, используйте класс LocalDate.

LocalDate.now( z );

Конкретный момент

Вы можете указать момент как количество миллисекунд с эпохи первого момента 1970 год по всемирному координированному времени.

long input = 1_234_567_898_765L ;
Instant instant = Instant.ofEpochMilli( input );

Instant.toString(): 2009-02-13T23:31:38.765Z

Z в этом выводе является сокращением от Zulu и означает UTC.

Вы можете назначить часовой пояс для настройки на определенное время настенных часов.

ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = instant.atZone( z );

zdt.toString(): 2009-02-13T18:31:38.765-05:00[Америка/Монреаль]

См. действующий код на IdeOne.com.

Я не рекомендую обмениваться данными о дате и времени таким образом. Лучше сериализовать текст в форматах ISO 8601. Например: 2009-02-13T23:31:38.765Z


О java.time

Платформа java.time встроен в Java 8 и более поздние версии. Эти классы заменяют проблемные старые устаревшие классы даты и времени, такие как java.util.Date, Calendar и SimpleDateFormat.

Проект Joda-Time, теперь в режим обслуживания, советует перейти на java.time.

Чтобы узнать больше, см. учебник по Oracle. И поищите множество примеров и пояснений в Stack Overflow. Спецификация: JSR 310.

Где получить классы java.time?

  • Java SE 8 and SE 9 and later
    • Built-in.
    • Часть стандартного Java API со встроенной реализацией.
    • Java 9 добавляет некоторые незначительные функции и исправления.
  • Java SE 6 and SE 7
    • Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
  • Android

Проект ThreeTen-Extra расширяет java.time дополнительными классами. Этот проект является испытательным полигоном для возможных дополнений к java.time в будущем. Здесь вы можете найти несколько полезных классов, таких как Interval, YearWeek, YearQuarter и подробнее.


Старый ответ - Joda-Time

Обновление: проект Joda-Time, теперь в режим обслуживания, рекомендуется переход на java.time.

  • Используйте Joda-Time 2.3 прямо сейчас.
  • В будущем с Java 8 рассмотрите возможность перехода на JSR 310: Date and Time API, который заменяет классы Date/Calendar и вдохновлен Joda-Time.

Пример кода

Сегодня

// © 2013 Basil Bourque. This source code may be used freely forever by anyone taking full responsibility for doing so.
// import org.joda.time.*;

// Generally best to be explicit about time zone rather than depend on default.
DateTimeZone denverTimeZone = DateTimeZone.forID( "America/Denver" );
java.util.Locale locale = Locale.FRANCE;

DateTime now = new DateTime( denverTimeZone );

System.out.println( "Current Year, Month & Day for: " + now );
System.out.println( "Year is " + now.year().getAsText( locale ) );
System.out.println( "Month is " + now.monthOfYear().getAsText( locale ) );
System.out.println( "Day is " + now.dayOfMonth().getAsText( locale ) );
System.out.println(); // blank line.

При запуске…

Current Year, Month & Day for: 2013-12-04T01:58:24.322-07:00
Year is 2013
Month is décembre
Day is 4

Когда-нибудь

// Not generally a good idea to focus on integers for working with date-time, but you asked for it.
DateTime someDateTime = new DateTime( 1234567898765L, DateTimeZone.UTC );

System.out.println( "Set Value of 1234567898765L is: " + someDateTime );
System.out.println( "Year is " + someDateTime.year().getAsText( locale ) );
System.out.println( "Month is " + someDateTime.monthOfYear().getAsText( locale ) );
System.out.println( "Day of month is " + someDateTime.dayOfMonth().getAsText( locale ) );
System.out.println( "Day of week is " + someDateTime.dayOfWeek().getAsText( locale ) );
System.out.println( "Day of year is " + someDateTime.dayOfYear().getAsText( locale ) );

При запуске…

Set Value of 1234567898765L is: 2009-02-13T23:31:38.765Z
Year is 2009
Month is février
Day of month is 13
Day of week is vendredi
Day of year is 44

P.S. У меня чуть не побежали мурашки по спине, когда я заметил, что ваш произвольно выбранный Лонг привел к Пятнице Тринадцатое!

person Basil Bourque    schedule 04.12.2013
comment
Василий, Спасибо за полное объяснение и пример Joda Time. Это действительно очень помогает. Я немного поиграю с этим и посмотрю, что из этого получится :) - person Kupcake69; 04.12.2013
comment
@Kupcake69 Чем больше вы знаете о Joda-Time, тем больше оно вам понравится. Joda-Time — одна из лучших причин для использования Java. Найдите в StackOverflow joda, чтобы найти много примеров и советов. Работа с датой и временем часто бывает сложной и запутанной, но Joda-Time очень помогает. - person Basil Bourque; 04.12.2013

По какой-то безумной причине класс Calendar использует нулевой индекс для месяца (январь == 0, февраль == 1 и т. д.), но все остальные части даты основаны на единице (соответствуют их фактическим числам).

Предположительно, это было сделано в какой-то неудачной попытке перечисления, но это просто глупо.

Мой совет — никогда не используйте Календарь. Вместо этого используйте Joda-Time.

person Bohemian♦    schedule 04.12.2013
comment
Спасибо, это действительно помогает. читая и проводя дополнительные исследования, я вижу, что существует некоторое предпочтение использованию Joda-Time. - person Kupcake69; 04.12.2013

Попробуйте использовать новую библиотеку даты и времени, предоставленную Java 8, которые вдохновлены Joda-Time и просты в использовании. Это также решило проблему с месяцем, начинающимся с 0.

person ravthiru    schedule 12.08.2016