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

org.neo4j.values.storable.LocalTimeValue Maven / Gradle / Ivy

There is a newer version: 5.25.1
Show newest version
/*
 * Copyright (c) "Neo4j"
 * Neo4j Sweden AB [http://neo4j.com]
 *
 * This file is part of Neo4j.
 *
 * Neo4j is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see .
 */
package org.neo4j.values.storable;

import java.time.Clock;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.OffsetTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalUnit;
import java.util.function.Supplier;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.neo4j.exceptions.InvalidArgumentException;
import org.neo4j.exceptions.UnsupportedTemporalUnitException;
import org.neo4j.values.AnyValue;
import org.neo4j.values.StructureBuilder;
import org.neo4j.values.ValueMapper;
import org.neo4j.values.virtual.MapValue;

import static java.lang.Integer.parseInt;
import static java.util.Objects.requireNonNull;
import static org.neo4j.memory.HeapEstimator.LOCAL_TIME_SIZE;
import static org.neo4j.memory.HeapEstimator.shallowSizeOfInstance;
import static org.neo4j.values.storable.DateTimeValue.parseZoneName;

public final class LocalTimeValue extends TemporalValue
{
    private static final long INSTANCE_SIZE = shallowSizeOfInstance( LocalTimeValue.class ) + LOCAL_TIME_SIZE;

    public static final LocalTimeValue MIN_VALUE = new LocalTimeValue( LocalTime.MIN );
    public static final LocalTimeValue MAX_VALUE = new LocalTimeValue( LocalTime.MAX );

    private final LocalTime value;

    private LocalTimeValue( LocalTime value )
    {
        this.value = value;
    }

    public static LocalTimeValue localTime( LocalTime value )
    {
        return new LocalTimeValue( requireNonNull( value, "LocalTime" ) );
    }

    public static LocalTimeValue localTime( int hour, int minute, int second, int nanosOfSecond )
    {
        return new LocalTimeValue( assertValidArgument( () -> LocalTime.of( hour, minute, second, nanosOfSecond ) ) );
    }

    public static LocalTimeValue localTime( long nanoOfDay )
    {
        return new LocalTimeValue( localTimeRaw( nanoOfDay ) );
    }

    public static LocalTime localTimeRaw( long nanoOfDay )
    {
        return assertValidArgument( () -> LocalTime.ofNanoOfDay( nanoOfDay ) );
    }

    public static LocalTimeValue parse( CharSequence text )
    {
        return parse( LocalTimeValue.class, PATTERN, LocalTimeValue::parse, text );
    }

    public static LocalTimeValue parse( TextValue text )
    {
        return parse( LocalTimeValue.class, PATTERN, LocalTimeValue::parse, text );
    }

    public static LocalTimeValue now( Clock clock )
    {
        return new LocalTimeValue( LocalTime.now( clock ) );
    }

    public static LocalTimeValue now( Clock clock, String timezone )
    {
        return now( clock.withZone( parseZoneName( timezone ) ) );
    }

    public static LocalTimeValue now( Clock clock, Supplier defaultZone )
    {
        return now( clock.withZone( defaultZone.get() ) );
    }

    public static LocalTimeValue build( MapValue map, Supplier defaultZone )
    {
        return StructureBuilder.build( builder( defaultZone ), map );
    }

    public static LocalTimeValue select( AnyValue from, Supplier defaultZone )
    {
        return builder( defaultZone ).selectTime( from );
    }

    public static LocalTimeValue truncate(
            TemporalUnit unit,
            TemporalValue input,
            MapValue fields,
            Supplier defaultZone )
    {
        LocalTime localTime = input.getLocalTimePart();
        LocalTime truncatedLT = assertValidUnit( () -> localTime.truncatedTo( unit ) );
        if ( fields.size() == 0 )
        {
            return localTime( truncatedLT );
        }
        else
        {
            return updateFieldMapWithConflictingSubseconds( fields, unit, truncatedLT,
                    ( mapValue, localTime1 ) -> {
                        if ( mapValue.size() == 0 )
                        {
                            return localTime( localTime1 );
                        }
                        else
                        {
                            return build( mapValue.updatedWith( "time", localTime( localTime1 ) ), defaultZone );
                        }
                    } );
        }
    }

    static final LocalTime DEFAULT_LOCAL_TIME = LocalTime.of( TemporalFields.hour.defaultValue, TemporalFields.minute.defaultValue );

    private static TimeValue.TimeBuilder builder( Supplier defaultZone )
    {
        return new TimeValue.TimeBuilder<>( defaultZone )
        {
            @Override
            protected boolean supportsTimeZone()
            {
                return false;
            }

            @Override
            public LocalTimeValue buildInternal()
            {
                LocalTime result;
                if ( fields.containsKey( TemporalFields.time ) )
                {
                    AnyValue time = fields.get( TemporalFields.time );
                    if ( !(time instanceof TemporalValue) )
                    {
                        throw new InvalidArgumentException( String.format( "Cannot construct local time from: %s", time ) );
                    }
                    result = ((TemporalValue) time).getLocalTimePart();
                }
                else
                {
                    result = DEFAULT_LOCAL_TIME;
                }

                result = assignAllFields( result );
                return localTime( result );
            }

            @Override
            protected LocalTimeValue selectTime(
                    AnyValue time )
            {

                if ( !(time instanceof TemporalValue) )
                {
                    throw new InvalidArgumentException( String.format( "Cannot construct local time from: %s", time ) );
                }
                TemporalValue v = (TemporalValue) time;
                LocalTime lt = v.getLocalTimePart();
                return localTime( lt );
            }
        };
    }

    @Override
    protected int unsafeCompareTo( Value otherValue )
    {
        LocalTimeValue other = (LocalTimeValue) otherValue;
        return value.compareTo( other.value );
    }

    @Override
    LocalTime temporal()
    {
        return value;
    }

    @Override
    public String getTypeName()
    {
        return "LocalTime";
    }

    @Override
    LocalDate getDatePart()
    {
        throw new UnsupportedTemporalUnitException( String.format( "Cannot get the date of: %s", this ) );
    }

    @Override
    LocalTime getLocalTimePart()
    {
        return value;
    }

    @Override
    OffsetTime getTimePart( Supplier defaultZone )
    {
        ZoneOffset currentOffset = assertValidArgument( () ->  ZonedDateTime.ofInstant( Instant.now(), defaultZone.get() ) ).getOffset();
        return OffsetTime.of( value, currentOffset );
    }

    @Override
    ZoneId getZoneId( Supplier defaultZone )
    {
        return defaultZone.get();
    }

    @Override
    ZoneOffset getZoneOffset()
    {
        throw new UnsupportedTemporalUnitException( String.format( "Cannot get the offset of: %s", this ) );
    }

    @Override
    public boolean supportsTimeZone()
    {
        return false;
    }

    @Override
    boolean hasTime()
    {
        return true;
    }

    @Override
    public boolean equals( Value other )
    {
        return other instanceof LocalTimeValue && value.equals( ((LocalTimeValue) other).value );
    }

    @Override
    public  void writeTo( ValueWriter writer ) throws E
    {
        writer.writeLocalTime( value );
    }

    @Override
    public String prettyPrint()
    {
        return assertPrintable( () -> value.format( DateTimeFormatter.ISO_LOCAL_TIME ) );
    }

    @Override
    public ValueRepresentation valueRepresentation()
    {
        return ValueRepresentation.LOCAL_TIME;
    }

    @Override
    protected int computeHashToMemoize()
    {
        return value.hashCode();
    }

    @Override
    public  T map( ValueMapper mapper )
    {
        return mapper.mapLocalTime( this );
    }

    @Override
    public LocalTimeValue add( DurationValue duration )
    {
        return replacement( assertValidArithmetic( () -> value.plusNanos( duration.nanosOfDay() ) ) );
    }

    @Override
    public LocalTimeValue sub( DurationValue duration )
    {
        return replacement( assertValidArithmetic( () -> value.minusNanos( duration.nanosOfDay() ) ) );
    }

    @Override
    LocalTimeValue replacement( LocalTime time )
    {
        return time == value ? this : new LocalTimeValue( time );
    }

    @Override
    public long estimatedHeapUsage()
    {
        return INSTANCE_SIZE;
    }

    static final String TIME_PATTERN = "(?:(?:(?[0-9]{1,2})(?::(?[0-9]{1,2})"
                                       + "(?::(?[0-9]{1,2})(?:[\\.,](?[0-9]{1,9}))?)?)?)|"
                                       + "(?:(?[0-9]{2})(?:(?[0-9]{2})"
                                       + "(?:(?[0-9]{2})(?:[\\.,](?[0-9]{1,9}))?)?)?))";
    private static final Pattern PATTERN = Pattern.compile( "(?:T)?" + TIME_PATTERN );

    private static LocalTimeValue parse( Matcher matcher )
    {
        return new LocalTimeValue( parseTime( matcher ) );
    }

    static LocalTime parseTime( Matcher matcher )
    {
        int hour;
        int minute;
        int second;
        int fraction;
        String longHour = matcher.group( "longHour" );
        if ( longHour != null )
        {
            hour = parseInt( longHour );
            minute = optInt( matcher.group( "longMinute" ) );
            second = optInt( matcher.group( "longSecond" ) );
            fraction = parseNanos( matcher.group( "longFraction" ) );
        }
        else
        {
            String shortHour = matcher.group( "shortHour" );
            hour = parseInt( shortHour );
            minute = optInt( matcher.group( "shortMinute" ) );
            second = optInt( matcher.group( "shortSecond" ) );
            fraction = parseNanos( matcher.group( "shortFraction" ) );
        }
        return assertParsable( () -> LocalTime.of( hour, minute, second, fraction ) );
    }

    private static int parseNanos( String value )
    {
        if ( value == null )
        {
            return 0;
        }
        int nanos = parseInt( value );
        if ( nanos != 0 )
        {
            for ( int i = value.length(); i < 9; i++ )
            {
                nanos *= 10;
            }
        }
        return nanos;
    }

    static int optInt( String value )
    {
        return value == null ? 0 : parseInt( value );
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy