net.time4j.WeekdayInMonthElement Maven / Gradle / Ivy
/*
* -----------------------------------------------------------------------
* Copyright © 2013-2016 Meno Hochschild,
* -----------------------------------------------------------------------
* This file (WeekdayInMonthElement.java) is part of project Time4J.
*
* Time4J is free software: You can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 2.1 of the License, or
* (at your option) any later version.
*
* Time4J is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Time4J. If not, see .
* -----------------------------------------------------------------------
*/
package net.time4j;
import net.time4j.base.GregorianMath;
import net.time4j.engine.ChronoEntity;
import net.time4j.engine.ChronoException;
import net.time4j.engine.ChronoOperator;
import net.time4j.format.NumericalElement;
import java.io.ObjectStreamException;
/**
* Das Element für den x-ten Wochentag im Monat.
*
* Eine Instanz ist erhältlich über den Ausdruck
* {@link PlainDate#WEEKDAY_IN_MONTH}. Diese Klasse bietet neben
* den vom Interface {@code AdjustableElement} geerbten Methoden
* weitere Spezialmethoden zum Setzen des Wochentags im Monat.
*
* @author Meno Hochschild
* @doctags.concurrency {immutable}
*/
final class WeekdayInMonthElement
extends AbstractDateElement
implements OrdinalWeekdayElement, NumericalElement {
//~ Statische Felder/Initialisierungen --------------------------------
/**
* Singleton.
*/
static final WeekdayInMonthElement INSTANCE = new WeekdayInMonthElement();
private static final int LAST = Integer.MAX_VALUE;
private static final long serialVersionUID = -2378018589067147278L;
//~ Konstruktoren -----------------------------------------------------
private WeekdayInMonthElement() {
super("WEEKDAY_IN_MONTH");
}
//~ Methoden ----------------------------------------------------------
@Override
public Class getType() {
return Integer.class;
}
@Override
public char getSymbol() {
return 'F';
}
@Override
public int numerical(Integer value) {
return value.intValue();
}
/**
* Definiert das Standardminimum.
*
* @return {@code 1}
*/
@Override
public Integer getDefaultMinimum() {
return Integer.valueOf(1);
}
/**
* Definiert das Standardmaximum.
*
* @return {@code 5}
*/
@Override
public Integer getDefaultMaximum() {
return Integer.valueOf(5);
}
@Override
public boolean isDateElement() {
return true;
}
@Override
public boolean isTimeElement() {
return false;
}
@Override
public ElementOperator setToFirst(Weekday dayOfWeek) {
return this.setTo(1, dayOfWeek);
}
@Override
public ElementOperator setToSecond(Weekday dayOfWeek) {
return this.setTo(2, dayOfWeek);
}
@Override
public ElementOperator setToThird(Weekday dayOfWeek) {
return this.setTo(3, dayOfWeek);
}
@Override
public ElementOperator setToFourth(Weekday dayOfWeek) {
return this.setTo(4, dayOfWeek);
}
@Override
public ElementOperator setToLast(Weekday dayOfWeek) {
return this.setTo(LAST, dayOfWeek);
}
@Override
public ElementOperator setTo(
int ordinal,
Weekday dayOfWeek
) {
return new SpecialOperator(ordinal, dayOfWeek);
}
@Override
protected boolean isSingleton() {
return true; // exists only once in PlainDate
}
private Object readResolve() throws ObjectStreamException {
return INSTANCE;
}
//~ Innere Klassen ----------------------------------------------------
private static class SpecialOperator
extends ElementOperator {
//~ Instanzvariablen ----------------------------------------------
private final int ordinal;
private final Weekday dayOfWeek;
private final ChronoOperator specialTS;
//~ Konstruktoren -------------------------------------------------
SpecialOperator(
int ordinal,
Weekday dayOfWeek
) {
super(WeekdayInMonthElement.INSTANCE, OP_WIM);
if (dayOfWeek == null) {
throw new NullPointerException("Missing value.");
}
this.ordinal = ordinal;
this.dayOfWeek = dayOfWeek;
this.specialTS = this::doApply;
}
//~ Methoden ------------------------------------------------------
@Override
public PlainDate apply(PlainDate entity) {
return this.doApply(entity);
}
@Override
ChronoOperator onTimestamp() {
return this.specialTS;
}
private > T doApply(T entity) {
if (entity.contains(PlainDate.CALENDAR_DATE)) {
PlainDate date = entity.get(PlainDate.CALENDAR_DATE);
Weekday current = date.get(PlainDate.DAY_OF_WEEK);
int delta = this.dayOfWeek.getValue() - current.getValue();
int dom = date.getDayOfMonth() + delta;
int days;
if (this.ordinal == LAST) {
days = (5 - (Math.floorDiv(dom - 1, 7) + 1)) * 7 + delta;
int max = GregorianMath.getLengthOfMonth(date.getYear(), date.getMonth());
if (date.getDayOfMonth() + days > max) {
days -= 7;
}
} else {
days = (this.ordinal - (Math.floorDiv(dom - 1, 7) + 1)) * 7 + delta;
}
date = date.plus(days, CalendarUnit.DAYS);
return entity.with(PlainDate.CALENDAR_DATE, date);
} else {
throw new ChronoException(
"Rule not found for ordinal day of week in month: "
+ entity);
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy