All Downloads are FREE. Search and download functionalities are using the official Maven repository.

gdv.xport.feld.Datum Maven / Gradle / Ivy

Go to download

gdv-xport-lib ist die Java-Bibliothek fuer den Umgang mit dem GDV-Format. Sie erleichtert den Export und Export dieses Datenformats.

There is a newer version: 7.2.2
Show newest version
/*
 * Copyright (c) 2009-2019 by Oliver Boehm
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express orimplied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * (c)reated 04.10.2009 by oliver ([email protected])
 */

package gdv.xport.feld;

import gdv.xport.config.Config;
import gdv.xport.util.SimpleConstraintViolation;
import net.sf.oval.ConstraintViolation;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import javax.validation.ValidationException;
import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.List;

/**
 * The Class Datum.
 *
 * @author oliver
 * @since 04.10.2009
 * @version $Revision$
 */
public final class Datum extends NumFeld {

    private static final Logger LOG = LogManager.getLogger(Feld.class);
    private static final Feld.Validator DEFAULT_VALIDATOR = new Datum.Validator(Config.getInstance());
    private final SimpleDateFormat dateFormat;

    /**
     * Dies ist der Copy-Constructor, mit dem man ein bestehendes Feld
     * kopieren kann.
     *
     * @param other das originale Feld
     */
    public Datum(final Feld other) {
        this(other, other.config);
    }

    private Datum(final Feld other, final Config cfg) {
        super(other, cfg);
        dateFormat = getDateFormat(other.getAnzahlBytes());
    }

    /**
     * Erstellt ein neues Datum.
     *
     * @param bezeichner Bezeichner
     * @param start the start
     * @since 2.0
     * @deprecated durch entsprechenden Constructor mit ByteAdresse ersetzt
     *             (TODO: wird mit v8 entsorgt)
     */
    @Deprecated
    public Datum(final Bezeichner bezeichner, final int start) {
        this(bezeichner, 8, start);
    }

    /**
     * Erstellt ein neues Datum.
     *
     * @param bezeichner Bezeichner
     * @param start the start
     * @since 7.0 (07-Jan-2024)
     */
    public Datum(final Bezeichner bezeichner, final ByteAdresse start) {
        this(bezeichner, 8, start);
    }

    /**
     * Erstellt ein neues Datum.
     *
     * @param name the name
     * @param start the start
     * @deprecated durch entsprechenden Constructor mit Bezeichner und ByteAdresse ersetzt
     *             (TODO: wird mit v8 entsorgt)
     */
    @Deprecated
    public Datum(final String name, final int start) {
        this(Bezeichner.of(name), 8, start);
    }

    /**
     * Instantiates a new datum.
     *
     * @param name the name
     * @param inhalt Datum der Form "ddmmjjjj" oder "ddjjjj" oder "dd"
     * @deprecated durch entsprechenden Constructor mit Bezeichner ersetzt
     *             (TODO: wird mit v8 entsorgt)
     */
    @Deprecated
    public Datum(final String name, final String inhalt) {
        this(name, inhalt.length(), 1, inhalt);
    }

    /**
     * Legt ein neues Datum an.
     *
     * @param bezeichner Bezeichner
     * @param length Anzahl Bytes
     * @param start Byte-Adresse
     * @deprecated durch entsprechenden Constructor mit ByteAdresse ersetzt
     *             (TODO: wird mit v8 entsorgt)
     */
    @Deprecated
    public Datum(Bezeichner bezeichner, int length, int start) {
        super(bezeichner, length, start);
        dateFormat = getDateFormat(length);
    }

    /**
     * Legt ein neues Datum an.
     *
     * @param bezeichner Bezeichner
     * @param length Anzahl Bytes
     * @param start Byte-Adresse
     * @since 7.0 (07-Jan-2024)
     */
    public Datum(Bezeichner bezeichner, int length, ByteAdresse start) {
        super(bezeichner, length, start);
        dateFormat = getDateFormat(length);
    }

    /**
     * Instantiates a new datum.
     *
     * @param name the name
     * @param length the length
     * @param start the start
     * @param inhalt Datum der Form "ddmmjjjj" oder "ddjjjj" oder "dd"
     * @deprecated durch entsprechenden Constructor mit Bezeichner und ByteAdresse ersetzt
     *             (TODO: wird mit v8 entsorgt)
     */
    @Deprecated
    public Datum(final String name, final int length, final int start, final String inhalt) {
        this(Bezeichner.of(name), length, start);
        this.setInhalt(inhalt);
    }

    /**
     * Legt ein neues Datum an.
     *
     * @param name   Bezeichner
     * @param length Laenge
     * @param start  Start-Adresse
     * @param inhalt Datum der Form "ddmmjjjj" oder "ddjjjj" oder "dd"
     * @since 7.0 (07-Jan-2024)
     */
    public Datum(final Bezeichner name, final int length, final ByteAdresse start, final String inhalt) {
        this(name, length, start);
        this.setInhalt(inhalt);
    }

    private Datum() {
        this(Bezeichner.of("Datum"), 8, 1);
    }

    /**
     * Dies ist der Copy-Constructor, mit dem man ein bestehendes Datum
     * kopieren kann.
     *
     * @param other das originale Feld
     */
    public Datum(final Datum other) {
        super(other);
        this.dateFormat = other.dateFormat;
    }

    /**
     * Liefert eine neues Datum mit neuer Konfiguration.
     *
     * @param c neue Konfiguration
     * @return neues Datzm
     * @since 6.1
     */
    @Override
    public Datum mitConfig(Config c) {
        return new Datum(this, c);
    }

    private static SimpleDateFormat getDateFormat(final int length) {
        return getDateFormat(length, "");
    }

    private static SimpleDateFormat getDateFormat(final int length, final String separator) {
        switch (length) {
            case 2:
                return new SimpleDateFormat("dd");
            case 4:
                return new SimpleDateFormat("MM" + separator + "yy");
            case 6:
                return new SimpleDateFormat("MM" + separator + "yyyy");
            case 8:
                return new SimpleDateFormat("dd" + separator + "MM" + separator + "yyyy");
            default:
                throw new IllegalArgumentException("length=" + length
                        + " not allowed - only 2, 4, 6 or 8");
        }
    }

    /**
     * Sets the inhalt.
     *
     * @param d the new inhalt
     */
    public void setInhalt(final Datum d) {
        this.setInhalt(d.getInhalt());
    }

    /**
     * Setzt den Inhalt anhand des uebergebenen Datums.
     *
     * @param d neues Datum
     */
    public void setInhalt(final Date d) {
        this.setInhalt(dateFormat.format(d));
    }

    @Override
    public void setInhalt(String neuerInhalt) {
        if (!isEmpty(neuerInhalt)) {
            Datum.Validator validator = (Datum.Validator) getValidator();
            String value = validator.verifyFormat(dateFormat, neuerInhalt);
        }
        super.setInhalt(neuerInhalt);
    }

    /**
     * Setzt den Inhalt anhand des uebergebenen Datums.
     *
     * @param localDate neues Datum
     * @since 5.0
     */
    public void setInhalt(final LocalDate localDate) {
        this.setInhalt(Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant()));
    }

    /**
     * Addiert den Summand auf und liefert das Datum als Zahl zurueck.
     *
     * @param anzahlTage Anzahl Tage
     * @return Summe
     * @since 5.0
     */
    @Override
    public BigDecimal add(BigDecimal anzahlTage) {
        LocalDate d = toLocalDate();
        d = d.plusDays(anzahlTage.intValue());
        setInhalt(d);
        return toBigDecimal();
    }

    /**
     * To date.
     *
     * @return the date
     */
    public Date toDate() {
        try {
            return dateFormat.parse(this.getInhalt());
        } catch (ParseException e) {
            throw new IllegalStateException(this + " has an invalid date (\""
                    + this.getInhalt() + "\")");
        }
    }

    /**
     * Wandelt das Datum in ein {@link LocalDate} um
     *
     * @return Datum als {@link LocalDate}
     * @since 5.0
     */
    public LocalDate toLocalDate() {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(dateFormat.toPattern());
        return LocalDate.parse(this.getInhalt(), formatter);
    }

    /**
     * Heute.
     *
     * @return the datum
     */
    public static Datum heute() {
        Datum d = new Datum();
        d.setInhalt(new Date());
        return d;
    }

    /* (non-Javadoc)
     * @see gdv.xport.feld.Feld#isEmpty()
     */
    @Override
    public boolean isEmpty() {
        if (super.isEmpty()) {
            return true;
        }
        return isEmpty(this.getInhalt());
    }

    private static boolean isEmpty(String value) {
        try {
            int n = Integer.parseInt(value);
            return n == 0;
        } catch (NumberFormatException e) {
            return false;
        }
    }

    /**
     * Aus Performance-Gruenden verwenden wir hier nicht die
     * validate()-Methode.
     *
     * @return true/false
     *
     * @see gdv.xport.feld.Feld#isValid()
     */
    @Override
    public boolean isValid() {
        if (this.isEmpty()) {
            return true;
        }
        return this.hasValidDate();
    }

    /* (non-Javadoc)
     * @see gdv.xport.feld.Feld#isInvalid()
     */
    @Override
    public boolean isInvalid() {
        return !this.isValid();
    }

    private boolean hasValidDate() {
        Datum.Validator validator = (Datum.Validator) getValidator();
        try {
            validator.validateFormat(dateFormat, this.getInhalt());
            return true;
        } catch (ValidationException e) {
            LOG.info(e + " -> mapped to false");
            return false;
        }
    }

    /* (non-Javadoc)
     * @see gdv.xport.feld.Feld#validate()
     */
    @Override
    public List validate() {
        List violations = super.validate();
        if (!this.isEmpty() && !this.hasValidDate()) {
            ConstraintViolation cv =
                    new SimpleConstraintViolation("'" + this.getInhalt() + "' is not a valid date", this);
            violations.add(cv);
        }
        return violations;
    }

    /* (non-Javadoc)
     * @see gdv.xport.feld.Feld#format()
     */
    @Override
    public String format() {
        DateFormat df = getDateFormat(this.getAnzahlBytes(), ".");
        return df.format(this.toDate());
    }

    /**
     * Liefert das Datumsformat zurueck, so wie es in der GDV-Beschreibung
     * steht.
     *
     * @return z.B. "TTMMJJJJ"
     * @since 6.2
     */
    public String getFormat() {
        return dateFormat.toPattern().replace('y', 'J').replace('d', 'T');
    }

    /* (non-Javadoc)
     * @see gdv.xport.feld.Feld#clone()
     */
    @SuppressWarnings("squid:S2975")
    @Override
    public Object clone() {
        return new Datum(this);
    }



    /**
     * Die Validierung von Datum-Felder ist etwas strikter als bei NumFeldern.
     * Einze Zahl ist nicht automatisch ein gueltiges Datum. Es muss schon mit
     * dem eingestellten Datumsformat uebereinstimmen.
     *
     * @since 6.2
     */
    public static class Validator extends NumFeld.Validator {

        public Validator() {
            super();
        }

        public Validator(Config config) {
            super(config);
        }

        protected String verifyFormat(DateFormat format, String value) {
            if ((getConfig().getValidateMode() == Config.ValidateMode.STRICT) && (format != null)) {
                try {
                    return validateFormat(format, value);
                } catch (ValidationException ex) {
                    throw new IllegalArgumentException("kein Datum: " + value, ex);
                }
            }
            return value;
        }

        protected String validateFormat(DateFormat format, String value) {
            try {
                Date date = format.parse(value);
                String converted = format.format(date);
                if (!value.equals(converted)) {
                    throw new ValidationException(String.format(
                            "'%s' ist kein korrektes Datum - ist vielleicht '%s' gemeint?", value, converted));
                }
            } catch (ParseException ex) {
                throw new ValidationException(String.format("'%s' ist kein Datum", value), ex);
            }
            return value;
        }

    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy