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

com.hp.hpl.jena.tdb.store.DateTimeNode Maven / Gradle / Ivy

There is a newer version: 0.8.10
Show newest version
/*
 * (c) Copyright 2008, 2009 Hewlett-Packard Development Company, LP
 * (c) Copyright 2010 Talis Systems Ltd.
 * All rights reserved.
 * [See end of file]
 */

package com.hp.hpl.jena.tdb.store;

import java.math.BigDecimal ;

import javax.xml.datatype.DatatypeConfigurationException ;
import javax.xml.datatype.DatatypeConstants ;
import javax.xml.datatype.DatatypeFactory ;
import javax.xml.datatype.XMLGregorianCalendar ;

import org.openjena.atlas.lib.BitsInt ;
import org.openjena.atlas.lib.BitsLong ;
import org.openjena.atlas.lib.NumberUtils ;

import com.hp.hpl.jena.tdb.TDBException ;

public class DateTimeNode
{
    // XXX ToDo 00:00:00 vs 24:00:00
    // ---- Layout
    // Epoch base: 0000-01-01T00:00:00

    // Layout:
    // Bits 56-63 : type
    
    // Bits 49-55 (7 bits)  : timezone -- 15 min precision + special for Z and no timezone.
    // Bits 27-48 (22 bits) : date, year is 13 bits = 8000 years  (0 to 7999)
    // Bits 0-26  (27 bits) : time, to milliseconds 

    // Layout:
    // Hi: TZ YYYY MM DD HH MM SS.sss Lo:

    // Const-ize
    static final int DATE_LEN = 22 ;    // 13 bits year, 4 bits month, 5 bits day => 22 bits
    static final int TIME_LEN = 27 ;    // 5 bits hour + 6 bits minute + 16 bits seconds (to millisecond)
    
    static final int MILLI = 0 ;
    static final int MILLI_LEN = 16 ;

    static final int MINUTES = MILLI_LEN ;
    static final int MINUTES_LEN = 6 ;

    static final int HOUR = MILLI_LEN + MINUTES_LEN ;
    static final int HOUR_LEN = 5 ;

    
    static final int DAY = TIME_LEN  ;
    static final int DAY_LEN = 5 ;

    static final int MONTH = TIME_LEN + DAY_LEN ;
    static final int MONTH_LEN = 4 ;
    
    static final int YEAR = TIME_LEN + MONTH_LEN + DAY_LEN ;
    static final int YEAR_LEN = 13 ;
    
    
    static final int TZ = TIME_LEN + DATE_LEN ;
    static final int TZ_LEN = 7 ;
    static final int TZ_Z = 0x7F ;      // Value for Z
    static final int TZ_NONE = 0x7E ;   // Value for no timezone.
    
    static DatatypeFactory datatypeFactory = null ;
    static
    { 
        try 
        { datatypeFactory = DatatypeFactory.newInstance() ; }
        catch (DatatypeConfigurationException ex)
        { throw new TDBException("DateTimeNode", ex) ; }
    }
    
    // Packed in correct place.
    static long time(long v, int hour, int mins, int millisec)
    {
        // And bit offset for direct packing?
        // HH:MM:SS.ssss => 5 bits H, 6 bits M, 16 bits S ==> 27 bits
        v = BitsLong.pack(v, hour, HOUR, HOUR+HOUR_LEN) ;
        v = BitsLong.pack(v, mins, MINUTES, MINUTES+MINUTES_LEN) ;
        v = BitsLong.pack(v, millisec, MILLI, MILLI+MILLI_LEN) ;
        return v ;
    }
    
    // Packed in correct place.
    static long date(long v, int year, int month, int day)
    {
        // YYYY:MM:DD => 13 bits year, 4 bits month, 5 bits day => 22 bits
        v = BitsLong.pack(v, year, YEAR, YEAR+YEAR_LEN) ;
        v = BitsLong.pack(v, month, MONTH, MONTH+MONTH_LEN) ;
        v = BitsLong.pack(v, day,  DAY, DAY+DAY_LEN) ;
        return v ;
    }
    
    static long tz(long v, int tz_in_quarters)
    {
        v = BitsLong.pack(v, tz_in_quarters, TZ, TZ+TZ_LEN);
        return v ;
    }

    // From string.  Assumed legal.  Retains all info this way.
    // returns -1 for unpackable. 
    public static long packDate(String lex)
    {
        return packDateTime(lex) ;
    }

    // From string.  Assumed legal.
    // Returns -1 for unpackable.
    
    public static long packDateTime(String lex)
    { 
        try { return packDateTime$(lex) ; }
        catch (Exception ex) { return -1 ; }
    }
    
    private static long packDateTime$(String lex)
    {
        long v = 0 ;
        // Whitespace facet processing.
        lex = lex.trim() ;
        
        boolean containsZ = (lex.indexOf('Z') > 0 ) ;
        
        // Bug in Java 1.6 (build 5 at least)
        // T24:00:00 not accepted.
        // See also TestNodeId.nodeId_date_time_7
        
        XMLGregorianCalendar xcal = datatypeFactory.newXMLGregorianCalendar(lex) ; ;
        
        if ( xcal.getFractionalSecond() != null )
        { 
            BigDecimal fs = xcal.getFractionalSecond() ;
            // Were there sub-millisecond resolution fractional seconds?
            // This isn't perfect but it needs a very long fractional part to break it,
            // less than observable quantum of time.
            if ( fs.doubleValue() != xcal.getMillisecond()/1000.0 )
                return -1 ;
        }
        
        int y = xcal.getYear() ;
        
        if ( y < 0 || y >= 8000 )
            return -1 ;
        
        v = date(v, xcal.getYear(), xcal.getMonth(), xcal.getDay() ) ;
        v = time(v, xcal.getHour(), xcal.getMinute(), xcal.getSecond()*1000+xcal.getMillisecond()) ;
        
        if ( containsZ )
            return tz(v, TZ_Z) ;
        
        int tz = xcal.getTimezone() ;
        if ( tz == DatatypeConstants.FIELD_UNDEFINED )
            return tz(v, TZ_NONE) ;

        // Timezone is weird. 
        if ( tz%15 != 0 )
            return -1 ;
        
        tz = tz/15 ;
        return tz(v, tz) ;
    }

    public static String unpackDateTime(long v)
    {
        return unpack(v, true) ;
    }

    public static String unpackDate(long v)
    {
        return unpack(v, false) ;
    }

    // Avoid calls to String.format
    private static String unpack(long v, boolean isDateTime)
    {
        // YYYY:MM:DD => 13 bits year, 4 bits month, 5 bits day => 22 bits
        int years = (int)BitsLong.unpack(v, YEAR, YEAR+YEAR_LEN) ;
        int months = (int)BitsLong.unpack(v, MONTH, MONTH+MONTH_LEN) ;
        int days = (int)BitsLong.unpack(v, DAY, DAY+DAY_LEN) ;
        
        // Hours: 5, mins 6, milli 16, TZ 7 => 34 bits 
        int hours = (int)BitsLong.unpack(v, HOUR, HOUR+HOUR_LEN) ;
        int minutes = (int)BitsLong.unpack(v, MINUTES, MINUTES+MINUTES_LEN) ; 
        int milliSeconds = (int)BitsLong.unpack(v, MILLI, MILLI+MILLI_LEN) ;
        
        int tz = (int)BitsLong.unpack(v, TZ, TZ+TZ_LEN);
        
        int sec = milliSeconds / 1000 ;
        int fractionSec = milliSeconds % 1000 ;
        
        StringBuilder sb = new StringBuilder(50) ;
        NumberUtils.formatInt(sb, years, 4) ;
        sb.append('-') ;
        NumberUtils.formatInt(sb, months, 2) ;
        sb.append('-') ;
        NumberUtils.formatInt(sb, days, 2) ;
        if ( isDateTime )
        {
            sb.append('T') ;
            NumberUtils.formatInt(sb, hours, 2) ;
            sb.append(':') ;
            NumberUtils.formatInt(sb, minutes, 2) ;
            sb.append(':') ;
            NumberUtils.formatInt(sb, sec, 2) ;

            // Formatting needed : int->any
            if ( fractionSec != 0 )
            {
                sb.append(".") ;
                // TODO Do better
                if ( fractionSec%100 == 0 )
                    NumberUtils.formatInt(sb, fractionSec/100, 1) ;
                else if ( fractionSec%10 == 0 )
                    NumberUtils.formatInt(sb, fractionSec/10, 2) ;
                else
                    NumberUtils.formatInt(sb, fractionSec, 3) ;
                
            }
        }
        // tz in 15min units
        

        if ( tz == TZ_Z )
        {
            sb.append("Z") ;
            return sb.toString();
        }
        
        if ( tz == TZ_NONE )
            return sb.toString() ; 
            
        // Sign extend.
        if ( BitsLong.isSet(v, TZ+TZ_LEN-1) )
            tz = BitsInt.set(tz, TZ_LEN, 32) ;
        
        int tzH = tz/4 ;
        int tzM = (tz%4)*15 ;
        NumberUtils.formatSignedInt(sb, tzH, 3) ; // Sign always included.
        sb.append(':') ;
        NumberUtils.formatInt(sb, tzM, 2) ;
        return sb.toString();
    }
}

/*
 * (c) Copyright 2008, 2009 Hewlett-Packard Development Company, LP
 * (c) Copyright 2010 Talis Systems Ltd.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */




© 2015 - 2025 Weber Informatics LLC | Privacy Policy