001/*
002 * Logback: the reliable, generic, fast and flexible logging framework.
003 * Copyright (C) 1999-2026, QOS.ch. All rights reserved.
004 *
005 * This program and the accompanying materials are dual-licensed under
006 * either the terms of the Eclipse Public License v2.0 as published by
007 * the Eclipse Foundation
008 *
009 *   or (per the licensee's choosing)
010 *
011 * under the terms of the GNU Lesser General Public License version 2.1
012 * as published by the Free Software Foundation.
013 */
014package ch.qos.logback.core.rolling.helper;
015
016import java.time.Instant;
017import java.time.ZoneId;
018import java.util.Date;
019import java.util.List;
020
021import ch.qos.logback.core.CoreConstants;
022import ch.qos.logback.core.pattern.DynamicConverter;
023import ch.qos.logback.core.util.CachingDateFormatter;
024import ch.qos.logback.core.util.DatePatternToRegexUtil;
025
026/**
027 * Returns a date formatted by {@link CachingDateFormatter}, which relies on
028 * {@link java.time.format.DateTimeFormatter}.
029 *
030 * @author Ceki Gülcü
031 */
032public class DateTokenConverter<E> extends DynamicConverter<E> implements MonoTypedConverter {
033
034    /**
035     * The conversion word/character with which this converter is registered.
036     */
037    public final static String CONVERTER_KEY = "d";
038    public final static String AUXILIARY_TOKEN = "AUX";
039    public static final String DEFAULT_DATE_PATTERN = CoreConstants.DAILY_DATE_PATTERN;
040
041    private String datePattern;
042    private ZoneId zoneId;
043    private CachingDateFormatter cdf;
044    // is this token converter primary or auxiliary? Only the primary converter
045    // determines the rolling period
046    private boolean primary = true;
047
048    public void start() {
049        this.datePattern = getFirstOption();
050        if (this.datePattern == null) {
051            this.datePattern = DEFAULT_DATE_PATTERN;
052        }
053
054        final List<String> optionList = getOptionList();
055        if (optionList != null) {
056            for (int optionIndex = 1; optionIndex < optionList.size(); optionIndex++) {
057                String option = optionList.get(optionIndex);
058                if (AUXILIARY_TOKEN.equalsIgnoreCase(option)) {
059                    primary = false;
060                } else {
061                    zoneId = ZoneId.of(option);
062                }
063            }
064        }
065
066        cdf = new CachingDateFormatter(datePattern, zoneId);
067    }
068
069    public String convert(Date date) {
070        return cdf.format(date.getTime());
071    }
072
073    public String convert(Instant instant) {
074        return cdf.format(instant.toEpochMilli());
075    }
076
077    public String convert(Object o) {
078        if (o == null) {
079            throw new IllegalArgumentException("Null argument forbidden");
080        }
081        if (o instanceof Date) {
082            return convert((Date) o);
083        }
084        if (o instanceof Instant) {
085            return convert((Instant) o);
086        }
087
088        throw new IllegalArgumentException("Cannot convert " + o + " of type" + o.getClass().getName());
089    }
090
091    /**
092     * Return the date pattern.
093     */
094    public String getDatePattern() {
095        return datePattern;
096    }
097
098    public ZoneId getZoneId() {
099        return zoneId;
100    }
101
102    public boolean isApplicable(Object o) {
103        if(o instanceof Date)
104            return true;
105        if(o instanceof Instant)
106            return true;
107        return false;
108    }
109
110    public String toRegex() {
111        DatePatternToRegexUtil datePatternToRegexUtil = new DatePatternToRegexUtil(datePattern);
112        return datePatternToRegexUtil.toRegex();
113    }
114
115    public boolean isPrimary() {
116        return primary;
117    }
118}