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

org.tinfour.gis.shapefile.DbfFieldDate Maven / Gradle / Ivy

Go to download

Classes for accessing data from GIS sources including Shapefiles and airborne Lidar

There is a newer version: 2.1.7
Show newest version
/* --------------------------------------------------------------------
 * Copyright (C) 2018  Gary W. Lucas.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * ---------------------------------------------------------------------
 */

 /*
 * -----------------------------------------------------------------------
 *
 * Revision History:
 * Date     Name         Description
 * ------   ---------    -------------------------------------------------
 * 12/2018  G. Lucas     Created  
 *
 * Notes:
 *
 * -----------------------------------------------------------------------
 */
package org.tinfour.gis.shapefile;

import java.io.IOException;
import java.time.Instant;
import java.time.ZonedDateTime;
import java.time.ZoneOffset;
import java.util.Arrays;
import org.tinfour.io.BufferedRandomAccessReader;

/**
 * Extends DbfField with special handling for reading date values.
 */
public class DbfFieldDate extends DbfField {

  private ZonedDateTime value;
  private ZoneOffset zoneOffset = ZoneOffset.UTC;

  DbfFieldDate(
          String name,
          char fieldType,
          int dataAddress,
          int fieldLength,
          int fieldDecimalCount,
          int offset) {
    super(name, fieldType, dataAddress, fieldLength, fieldDecimalCount, offset);
  }

  private int scan1(int b, StringBuilder sb) throws IOException {
    sb.append((char) b);
    if (b < 48 || b > 57) {
      if (Character.isWhitespace((char) b)) {
        return 0;
      } else {
        throw new IOException("Invalid character (" + b
                + ") where numeric expected in date field");
      }
    }
    return b - 48;
  }

  @Override
  void read(BufferedRandomAccessReader brad, long recordFilePos) throws IOException {
    brad.seek(recordFilePos + offset);

    // The date format is simply YYYYMMDD
    builder.setLength(0);
    int y0 = scan1(brad.readUnsignedByte(), builder);
    int y1 = scan1(brad.readUnsignedByte(), builder);
    int y2 = scan1(brad.readUnsignedByte(), builder);
    int y3 = scan1(brad.readUnsignedByte(), builder);
    int year = ((y0 * 10 + y1) * 10 + y2) * 10 + y3;
    
    int m1 = scan1(brad.readUnsignedByte(), builder);
    int m2 = scan1(brad.readUnsignedByte(), builder);
    int month = m1 * 10 + m2;
    
    int d1 = scan1(brad.readUnsignedByte(), builder);
    int d2 = scan1(brad.readUnsignedByte(), builder);
    int day = d1 * 10 + d2;
    if(year==0 || month==0 || day==0){
      value = null;
    }else{
      value = ZonedDateTime.of(year, month, day, 0, 0, 0, 0, zoneOffset);
    }
  }

  /**
   * Gets the value stored in the field during the most recent read as a
   * floating point value giving seconds since the Epoch 1970.
   *
   * @return a valid double or a NaN if the file content was invalid
   */
  @Override
  public double getDouble() {
    if (value == null) {
      return Double.NaN;
    }
    return value.toEpochSecond() * 1000.0;
  }

  /**
   * Gets an integer value indicating whether the data field has been correctly
   * read.
   * 

* Although it would be tempting to make this field return an conventional * integer representation of seconds since Epoch 1970, a 32 bit integer value * will overflow and become undefined on 03:14:07 UTC on 19 January 2038. If * you require an integer time value, please use the getLong() method. * * @return a value of -1 if the field is uninitialized or zero if it is * initialized. */ @Override public int getInteger() { if (value == null) { return 0; } return (int) value.toEpochSecond(); } /** * Gets the date value as an long integer time value consistent with the Java * convention using Epoch 1970. * * @return an integer value; zero if undefined. */ public long getLong() { if (value == null) { return 0; } return value.toEpochSecond() * 1000L; } @Override public Object getApplicationData() { return value; } /** * Gets a ZonedDateTime instance representing the value extracted from the * file. * * @return a valid local date time. */ public ZonedDateTime getValue() { return value; } /** * Gets an array of unique values for this field. * * @param dbf a valid instance * @return if successful an array of zero or more elements. * @throws IOException in the event of an unrecoverable I/O condition. */ public ZonedDateTime[] getUniqueValueArray(DbfFileReader dbf) throws IOException { long vMin = Long.MAX_VALUE; long vMax = Long.MIN_VALUE; int nRecords = dbf.getRecordCount(); if (nRecords == 0) { return new ZonedDateTime[0]; } long[] vArray = new long[nRecords]; int k = 0; for (int i = 1; i <= nRecords; i++) { dbf.readField(i, this); if(isNull()){ continue; } long v = getLong(); if (v < vMin) { vMin = v; } if (v > vMax) { vMax = v; } vArray[k++] = v; } Arrays.sort(vArray, 0, k); int nUniqueValues = 1; long prior = vArray[0]; for (int i = 1; i < k; i++) { if (vArray[i] != prior) { prior = vArray[i]; vArray[nUniqueValues] = vArray[i]; nUniqueValues++; } } ZonedDateTime[] ldtArray = new ZonedDateTime[nUniqueValues]; for (int i = 0; i < nUniqueValues; i++) { Instant instant = Instant.ofEpochMilli(vArray[i]); ldtArray[i] = ZonedDateTime.ofInstant(instant, ZoneOffset.UTC); } return ldtArray; } /** * Sets the zone offset to be used when reading data * * @param zoneOffset a valid instance */ public void setZoneOffset(ZoneOffset zoneOffset) { if (zoneOffset == null) { throw new NullPointerException("Null zone-offset value not supported"); } this.zoneOffset = zoneOffset; } @Override public boolean isNull(){ return value==null; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy