001/*
002 * Copyright (c) 2015-2020, Oracle and/or its affiliates. All rights reserved.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.tribuo.data.columnar.extractors;
018
019import com.oracle.labs.mlrg.olcut.config.Config;
020import com.oracle.labs.mlrg.olcut.provenance.ConfiguredObjectProvenance;
021import com.oracle.labs.mlrg.olcut.provenance.impl.ConfiguredObjectProvenanceImpl;
022
023import java.time.LocalDate;
024import java.time.format.DateTimeFormatter;
025import java.time.format.DateTimeParseException;
026import java.util.Optional;
027import java.util.logging.Level;
028import java.util.logging.Logger;
029
030/**
031 * Extracts the field value and translates it to a {@link LocalDate} based on the specified {@link DateTimeFormatter}.
032 * <p>
033 * Returns an empty optional if the date failed to parse.
034 */
035public class DateExtractor extends SimpleFieldExtractor<LocalDate> {
036    private static final Logger logger = Logger.getLogger(DateExtractor.class.getName());
037
038    @Config(mandatory = true, description = "The expected date format.")
039    private String dateFormat;
040    private DateTimeFormatter formatter;
041
042    /**
043     * for olcut
044     */
045    private DateExtractor() {}
046
047    /**
048     * Constructs a date extractor that emits a LocalDate by applying the supplied format to the specified field.
049     * @param fieldName The field to read.
050     * @param metadataName The metadata field to write.
051     * @param dateFormat The date format (supplied to {@link DateTimeFormatter}.
052     */
053    public DateExtractor(String fieldName, String metadataName, String dateFormat) {
054        super(fieldName, metadataName);
055        this.dateFormat = dateFormat;
056        postConfig();
057    }
058
059    /**
060     * Constructs a date extractor that emits a LocalDate by applying the supplied format to the specified field.
061     * <p>
062     * Deprecated as it does not allow recovery of the formatter pattern for the provenance.
063     * @param fieldName The field to read.
064     * @param metadataName The metadata field to write.
065     * @param formatter The date format (supplied to {@link DateTimeFormatter}.
066     */
067    @Deprecated
068    public DateExtractor(String fieldName, String metadataName, DateTimeFormatter formatter) {
069        super(fieldName, metadataName);
070        this.formatter = formatter;
071    }
072
073    /**
074     * Used by the OLCUT configuration system, and should not be called by external code.
075     */
076    @Override
077    public void postConfig() {
078        if (dateFormat != null) {
079            formatter = DateTimeFormatter.ofPattern(dateFormat);
080        } else {
081            formatter = DateTimeFormatter.BASIC_ISO_DATE;
082        }
083        if (metadataName == null || metadataName.isEmpty()) {
084            metadataName = fieldName;
085        }
086    }
087
088    @Override
089    public Class<LocalDate> getValueType() {
090        return LocalDate.class;
091    }
092
093    @Override
094    protected Optional<LocalDate> extractField(String s) {
095        try {
096            return Optional.of(LocalDate.parse(s, formatter));
097        } catch (DateTimeParseException e) {
098            logger.log(Level.WARNING, e.getParsedString());
099            logger.log(Level.WARNING, String.format("Unable to parse date %s with formatter %s", s, formatter.toString()));
100            return Optional.empty();
101        }
102    }
103
104    @Override
105    public String toString() {
106        return "DateExtractor(fieldName=" + fieldName + ", metadataName=" + metadataName + ", dateFormat=" + formatter.toString() + ")";
107    }
108
109    @Override
110    public ConfiguredObjectProvenance getProvenance() {
111        return new ConfiguredObjectProvenanceImpl(this, "DateExtractor");
112    }
113}