2017-02-02 6 views
1

Я хочу получить дату понедельника с данной недели и года, используя Java 8-пакет java.time. Но в какой-то момент я столкнулся с проблемой, поскольку она не возвращает правильную дату.получение даты понедельника с данной недели и года с использованием пакета java.time

private LocalDate getDateFromWeekAndYear(final String week,final String year){ 
    LocalDate date = LocalDate.now(); 
    date = date.with(WeekFields.ISO.dayOfWeek(), 1); 
    date = date.with(WeekFields.ISO.weekOfWeekBasedYear(), Long.parseLong(week)); 
    date = date.with(WeekFields.ISO.weekBasedYear(), Long.parseLong(year)); 

    return date; 
} 

Например:

  • Если я прохожу неделю = 1 и год = 2013 затем дата: 2012-12-31.
  • Но если я пройду неделю = 53 и год = 2015, то дата: 2014-12-29. Я ожидал 2014-12-28.

Есть ли какая-то логическая ошибка, которую я делаю или какая-то другая проблема?

+0

Вы имеете в виду получение текущей даты с использованием YearMonth.of (int year, int month)? –

+1

29/12/2014 был понедельник - почему вы ожидаете 28/12/2014? Также обратите внимание, что было бы более понятным использовать 'DayOfWeek.MONDAY.getValue()' вместо '1'. – assylias

+1

Вам не нужна информация текущей даты, нет необходимости начинать с этого. Вы можете установить неделю и год с помощью 'YearMonth.of (int year, int month)', а затем установить день недели. – Aaron

ответ

2

Это удивительно сложнее, чем частично недействительные ожидания ОП и большинство ответов.

Прежде всего, нужно сказать: очень важно определить правильный порядок действий, основанных на недельных манипуляциях. OP впервые применил дневные манипуляции, а затем манипулирование на основе года. Правильный подход обратный! Я покажу правильную реализацию методы хелперов:

public static void main(String... args) { 
    System.out.println(
     getDateFromWeekAndYear("53", "2015")); // 2015-12-28, NOT 2014-12-28 
    System.out.println(
     getDateFromWeekAndYear("53", "2015").get(WeekFields.ISO.weekOfWeekBasedYear())); // 53 
    System.out.println(
     getDateFromWeekAndYear("53", "2014")); // 2014-12-29 
    System.out.println(
     getDateFromWeekAndYear("53", "2014").get(WeekFields.ISO.weekOfWeekBasedYear())); // 1 
} 

private static LocalDate getDateFromWeekAndYear(final String week,final String year) { 
    int y = Integer.parseInt(year); 
    LocalDate date = LocalDate.of(y, 7, 1); // safer than choosing current date 
    // date = date.with(WeekFields.ISO.weekBasedYear(), y); // no longer necessary 
    date = date.with(WeekFields.ISO.weekOfWeekBasedYear(), Long.parseLong(week)); 
    date = date.with(WeekFields.ISO.dayOfWeek(), 1); 

    return date; 
} 

Если вы не уважаете этот конкретный заказ, то вы действительно получите иногда в 2014-дату для ввода 2015-W53 (в зависимости от текущей даты).

Вторая проблема: Я также избегаю начинать с текущей даты, чтобы быть не ближе к началу или концу календарного года (календарный год! = Неделя по году), а вместо этого выбрана в середине года в качестве отправной точки ,

Третья проблема заключается в мягкой обработке недели 53 в неделю (неделя) 2014 года. Этого не существует, потому что 2014 года было всего 52 недели !!! Строгий алгоритм должен распознавать и отклонять такой ввод. Поэтому я советую не использовать YearWeek.of(2014, 53) (во внешней библиотеке Threeten-Extra), что приводит к первой неделе 2015 года, см. Также ее javadoc. Лучше, чем такое снисходительное обращение было бы

YearWeek yw = YearWeek.of(2014, 52); 
if (yw.is53WeekYear()) { 
    yw = YearWeek.of(2014, 53); 
} 

или используя этот код из моей библиотеки времени Time4J (чей класс CalendarWeek имеет дополнительные i18n-функции и дополнительные недели арифметику по сравнению с YearWeek):

CalendarWeek.of(2014, 53); // throws an exception 
System.out.println(CalendarWeek.of(2014, 1).withLastWeekOfYear()); // 2014-W52 

только с помощью java.time -package:

Использование таких внешних библиотек, по крайней мере, помогли решить первую пробл em прозрачным способом.Если вы не хотите добавлять дополнительную зависимость, вы можете сделать это, чтобы обработать неделю 53, если это недействительно:

Если выражение WeekFields.ISO.weekOfWeekBasedYear(), примененное к результату вашего вспомогательного метода, дает значение 1, тогда вы знаете, что неделя 53 была недействительной , И тогда вы можете решить, хотите ли вы принять мягкую обработку или выбросить исключение. Но тихая настройка такого недопустимого ввода - это плохой дизайн IMHO.

+0

спасибо за ответ. Это действительно устранило мои сомнения. Я применял неправильный порядок для получения даты. –

-1

Первый день недели - воскресенье. Я думаю, проблема здесь

+0

Первый день недели - понедельник в java время. – assylias

+0

Ну, мой плохой тогда –

+3

@assylias monday - первый день в стандартах ИСО, так как запрашивается код в вопросе; это не обязательно первый день недели вообще в java время, это зависит от локали. – Gimby

2

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

public static LocalDate firstMonday(int week, int year) { 

    LocalDate firstMonOfFirstWeek = LocalDate.now() 
      .with(IsoFields.WEEK_BASED_YEAR, year) // year 
      .with(IsoFields.WEEK_OF_WEEK_BASED_YEAR, 1) // First week of the year 
      .with(ChronoField.DAY_OF_WEEK, 1); // Monday 

    // Plus multi of 7 
    return firstMonOfFirstWeek.plusDays((week - 1) * 7); 
} 

public static void main(String[] args) { 
    System.out.println(firstMonday(1, 2013)); // 2012-12-31 
    System.out.println(firstMonday(53 ,2015)); // 2015-12-28 
} 
1

Т.Л., д-р

YearWeek.of (2013 , 1).atDay (DayOfWeek.MONDAY) 

Неверные ожидания

Ваши ожидания не являются правильными. Понедельник 2015-W53 - 2015-12-28, а не 2014-12-28, год 2015, а не 2014. Нет причин ожидать 2014. Пожалуйста, отредактируйте свой вопрос, чтобы объяснить свои мысли, если вам нужно больше объяснений.

Вы можете быть смущены в отношении календарного года по сравнению с недельным годом. В ISO 8601 definition of a week based year, неделя номер один содержит первый четверг календарного года. Это означает, что мы имеем некоторое совпадение между годами. Последние несколько дней календарного года могут проживать в следующем недельном году. И наоборот, первые несколько дней календарного года могут проживать в предыдущем недельном году.

В качестве примера вы можете увидеть на скриншоте ниже, последний день календаря 2012 года (31 декабря) выпадает на неделю первой недели недели 2013 года на неделю №1. На другом экране выстрел, мы имеем обратное, где первые три дня календаря 2016 года (1 января, 2, 3) & земли в неделю на основе года 2015 на номер недели 53.

  • понедельник из 2013-W01 является 2012-12-31.
  • Понедельник 2015-W53 является 2015-12-28.

2013-W01 calendar screen shot

2015-W53 calendar screen shot

YearWeek

Я предлагаю добавить в ThreeTen-Extra библиотеку для вашего проекта, чтобы использовать в YearWeek класса. Вместо того, чтобы пропускать только целые числа в течение года и недели, обходите объекты этого класса.Это делает ваш код более самодокументированным, обеспечивает безопасность по типу и обеспечивает допустимые значения.

// Pass (week-based-year-number, week-number). *Not* calendar year! See the ISO 8601 standard. 
YearWeek yw = YearWeek.of(2013 , 1); 

Вы можете вытащить любой день с этой недели.

LocalDate ld = yw.atDay(DayOfWeek.MONDAY); 

Давайте попробуем такой код.

YearWeek yw1 = YearWeek.of (2013 , 1); 
LocalDate ld1 = yw1.atDay (DayOfWeek.MONDAY); 

YearWeek yw2 = YearWeek.of (2015 , 53); 
LocalDate ld2 = yw2.atDay (DayOfWeek.MONDAY); 

System.out.println ("yw1: " + yw1 + " Monday: " + ld1); 
System.out.println ("yw2: " + yw2 + " Monday: " + ld2); 

yw1: 2013-W01 Понедельник: 2012-12-31

YW2: 2015-W53 Понедельник: 2015-12-28


Совет: Для того, чтобы увидеть те номера ISO 8601 standard week на Mac в Calendar.app, set System Preferences>Language & Region>Calendar>ISO 8601. Затем в Calendar.app установите Preferences>Advanced>Show week numbers.

+1

Нет, неверные ожидания, см. Мой ответ. –

+1

@MenoHochschild Я просто неправильно читал «2014» в вопросе «2015», сосредоточившись на соответствующем месяце 12 и 28 дня. Я исправил свой ответ, обратив мое утверждение о «правильных ожиданиях». Спасибо за критику. –

+1

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

Смежные вопросы