001    /*
002     *  Licensed to the Apache Software Foundation (ASF) under one
003     *  or more contributor license agreements.  See the NOTICE file
004     *  distributed with this work for additional information
005     *  regarding copyright ownership.  The ASF licenses this file
006     *  to you under the Apache License, Version 2.0 (the
007     *  "License"); you may not use this file except in compliance
008     *  with the License.  You may obtain a copy of the License at
009     *  
010     *    http://www.apache.org/licenses/LICENSE-2.0
011     *  
012     *  Unless required by applicable law or agreed to in writing,
013     *  software distributed under the License is distributed on an
014     *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015     *  KIND, either express or implied.  See the License for the
016     *  specific language governing permissions and limitations
017     *  under the License. 
018     *  
019     */
020    
021    package org.apache.directory.server.ntp.messages;
022    
023    
024    import java.nio.ByteBuffer;
025    import java.text.SimpleDateFormat;
026    import java.util.Date;
027    import java.util.TimeZone;
028    
029    
030    /**
031     * NTP timestamps are represented as a 64-bit unsigned fixed-point number,
032     * in seconds relative to 0h on 1 January 1900. The integer part is in the
033     * first 32 bits and the fraction part in the last 32 bits. In the fraction
034     * part, the non-significant low order can be set to 0.
035     * 
036     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
037     * @version $Rev: 547539 $, $Date: 2007-06-15 08:08:06 +0200 (Fri, 15 Jun 2007) $
038     */
039    public class NtpTimeStamp
040    {
041        /**
042         * The number of milliseconds difference between the Java epoch and
043         * the NTP epoch ( January 1, 1900, 00:00:00 GMT ).
044         */
045        private static final long NTP_EPOCH_DIFFERENCE = -2208988800000L;
046    
047        private static final TimeZone UTC_TIME_ZONE = TimeZone.getTimeZone( "UTC" );
048        private static final SimpleDateFormat dateFormat = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss.SSS z" );
049    
050        static
051        {
052            dateFormat.setTimeZone( UTC_TIME_ZONE );
053        }
054    
055        private long seconds = 0;
056        private long fraction = 0;
057    
058    
059        /**
060         * Creates a new instance of NtpTimeStamp that represents the time "right now."
061         */
062        public NtpTimeStamp()
063        {
064            this( new Date() );
065        }
066    
067    
068        /**
069         * Creates a new instance of NtpTimeStamp that represents the given {@link Date}.
070         *
071         * @param date
072         */
073        public NtpTimeStamp( Date date )
074        {
075            long msSinceStartOfNtpEpoch = date.getTime() - NTP_EPOCH_DIFFERENCE;
076    
077            seconds = msSinceStartOfNtpEpoch / 1000;
078            fraction = ( ( msSinceStartOfNtpEpoch % 1000 ) * 0x100000000L ) / 1000;
079        }
080    
081    
082        /**
083         * Creates a new instance of NtpTimeStamp from encoded data in a {@link ByteBuffer}.
084         *
085         * @param data
086         */
087        public NtpTimeStamp( ByteBuffer data )
088        {
089            for ( int ii = 0; ii < 4; ii++ )
090            {
091                seconds = 256 * seconds + makePositive( data.get() );
092            }
093    
094            for ( int ii = 4; ii < 8; ii++ )
095            {
096                fraction = 256 * fraction + makePositive( data.get() );
097            }
098        }
099    
100    
101        /**
102         * Writes this {@link NtpTimeStamp} to the given {@link ByteBuffer}.
103         *
104         * @param buffer
105         */
106        public void writeTo( ByteBuffer buffer )
107        {
108            byte[] bytes = new byte[8];
109    
110            long temp = seconds;
111            for ( int ii = 3; ii >= 0; ii-- )
112            {
113                bytes[ii] = ( byte ) ( temp % 256 );
114                temp = temp / 256;
115            }
116    
117            temp = fraction;
118            for ( int ii = 7; ii >= 4; ii-- )
119            {
120                bytes[ii] = ( byte ) ( temp % 256 );
121                temp = temp / 256;
122            }
123    
124            buffer.put( bytes );
125        }
126    
127    
128        public String toString()
129        {
130            long msSinceStartOfNtpEpoch = seconds * 1000 + ( fraction * 1000 ) / 0x100000000L;
131            Date date = new Date( msSinceStartOfNtpEpoch + NTP_EPOCH_DIFFERENCE );
132    
133            synchronized ( dateFormat )
134            {
135                return "org.apache.ntp.message.NtpTimeStamp[ date = " + dateFormat.format( date ) + " ]";
136            }
137        }
138    
139    
140        public boolean equals( Object o )
141        {
142            if ( this == o )
143            {
144                return true;
145            }
146    
147            if ( !( o instanceof NtpTimeStamp ) )
148            {
149                return false;
150            }
151    
152            NtpTimeStamp that = ( NtpTimeStamp ) o;
153            return ( this.seconds == that.seconds ) && ( this.fraction == that.fraction );
154        }
155    
156    
157        private int makePositive( byte b )
158        {
159            int byteAsInt = b;
160            return ( byteAsInt < 0 ) ? 256 + byteAsInt : byteAsInt;
161        }
162    }