ucar.nc2.iosp.grads.GradsTimeDimension Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of netcdf Show documentation
Show all versions of netcdf Show documentation
The NetCDF-Java Library is a Java interface to NetCDF files,
as well as to many other types of scientific data formats.
The newest version!
/*
* Copyright 1998-2011 University Corporation for Atmospheric Research/Unidata
*
* Portions of this software were developed by the Unidata Program at the
* University Corporation for Atmospheric Research.
*
* Access and use of this software shall impose the following obligations
* and understandings on the user. The user is granted the right, without
* any fee or cost, to use, copy, modify, alter, enhance and distribute
* this software, and any derivative works thereof, and its supporting
* documentation for any purpose whatsoever, provided that this entire
* notice appears in all copies of the software, derivative works and
* supporting documentation. Further, UCAR requests that the user credit
* UCAR/Unidata in any publications that result from the use of this
* software or in any product that includes this software. The names UCAR
* and/or Unidata, however, may not be used in any advertising or publicity
* to endorse or promote any products or commercial entity unless specific
* written permission is obtained from UCAR/Unidata. The user also
* understands that UCAR/Unidata is not obligated to provide the user with
* any support, consulting, training or assistance of any kind with regard
* to the use, operation and performance of this software nor to provide
* the user with any updates, revisions, new versions or "bug fixes."
*
* THIS SOFTWARE IS PROVIDED BY UCAR/UNIDATA "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 UCAR/UNIDATA BE LIABLE FOR ANY SPECIAL,
* INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
* FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
* WITH THE ACCESS, USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/**
*
*/
package ucar.nc2.iosp.grads;
import ucar.nc2.units.DateUnit;
import java.text.FieldPosition;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;
/**
* Class to hold the complexities of the GrADS time dimension
*
* @author Don Murray - CU/CIRES
*/
public class GradsTimeDimension extends GradsDimension {
/** time increment periods */
private final String[] incStr = { "mn", "hr", "dy", "mo", "yr" };
/** corresponding Calendar periods */
private final int[] calIncs = { Calendar.MINUTE, Calendar.HOUR,
Calendar.DATE, Calendar.MONTH,
Calendar.YEAR };
/** time date formats (input is lowercased so Z is z) */
private final String[] dateFormats = { "HH:mm'z'ddMMMyyyy",
"HH'z'ddMMMyyyy", "ddMMMyyyy",
"MMMyyyy" };
/** The initial time as a TimeStruct */
private GradsTimeStruct initialTime = null;
//J-
/** time templates */
private static final String[] timeTemplates = {
"%x1", // 1 digit decade
"%x3", // 3 digit decade
"%y2", // 2 digit year
"%y4", // 4 digit year
"%m1", // 1 or 2 digit month
"%m2", // 2 digit month (leading zero if needed)
"%mc", // 3 character month abbreviation
"%d1", // 1 or 2 digit day
"%d2", // 2 digit day (leading zero if needed)
"%h1", // 1 or 2 digit hour
"%h2", // 2 digit hour
"%h3", // 3 digit hour (e.g., 120 or 012)
"%n2", // 2 digit minute; leading zero if needed
"%f2", // 2 digit forecast hour; leading zero if needed; more digits added for hours >99; hour values increase indefinitely
"%f3", // 3 digit forecast hour; leading zeros if needed; more digits added for hours >999; hour values increase indefinitely
"%fn2", // 2 digit forecast minute; leading zero if needed; more digits added for minutes > 99; minute values increase indefinitely (2.0.a9+)
"%fhn", // forecast time expressed in hours and minutes (hhnn) where minute value (nn) is always <=59
// and hour value (hh) increases indefinitely. If hh or nn are <=9, they are padded with a 0
// so they are always at least 2 digits; more digits added for hours >99. (2.0.a9+)
"%fdhn", // forecast time expressed in days, hours, and minutes (ddhhnn) where minute value (nn) is always <=59,
// hour value (hh) is always <=23 and day value (dd) increases indefinitely. If dd, hh, or nn are <=9,
// they are padded with a 0 so they are always at least 2 digits; more digits added for days >99. (2.0.a9+)
"%j3", // 3 digit julian day (day of year) (2.0.a7+)
"%t1", // 1 or 2 digit time index (file names contain number sequences that begin with 1 or 01) (2.0.a7+)
"%t2", // 2 digit time index (file names contain number sequences that begin with 01) (2.0.a7+)
"%t3", // 3 digit time index (file names contain number sequences that begin with 001) (2.0.a7+)
"%t4", // 4 digit time index (file names contain number sequences that begin with 0001) (2.0.a8+)
"%t5", // 5 digit time index (file names contain number sequences that begin with 00001) (2.0.a8+)
"%t6", // 6 digit time index (file names contain number sequences that begin with 000001) (2.0.a8+)
"%tm1", // 1 or 2 digit time index (file names contain number sequences that begin with 0 or 00) (2.0.a7+)
"%tm2", // 2 digit time index (file names contain number sequences that begin with 00) (2.0.a7+)
"%tm3", // 3 digit time index (file names contain number sequences that begin with 000) (2.0.a7+)
"%tm4", // 4 digit time index (file names contain number sequences that begin with 0000) (2.0.a8+)
"%tm5", // 5 digit time index (file names contain number sequences that begin with 00000) (2.0.a8+)
"%tm6", // 6 digit time index (file names contain number sequences that begin with 000000) (2.0.a8+)
//When specifying the initial time (e.g., NWP model output), use these substitutions:
"%ix1", //initial 1 digit decade
"%ix3", //initial 3 digit decade
"%iy2", //initial 2 digit year
"%iy4", //initial 4 digit year
"%im1", //initial 1 or 2 digit month
"%im2", //initial 2 digit month (leading zero if needed)
"%imc", //initial 3 character month abbreviation
"%id1", //initial 1 or 2 digit day (leading zero if needed)
"%id2", //initial 2 digit day
"%ih1", //initial 1 or 2 digit hour
"%ih2", //initial 2 digit hour
"%ih3", //initial 3 digit hour
"%in2" //initial 2 digit minute (leading zero if needed)
};
//J+
/**
* Create new GradsTimeDimension
*
* @param name the dimension name
* @param size the dimension size
* @param mapping the dimension mapping type
*/
public GradsTimeDimension(String name, int size, String mapping) {
super(name, size, mapping);
}
/**
* Make the level values from the specifications
*
* @return the level values
*/
protected double[] makeLevelValues() {
List levels = getLevels();
if (levels == null) {
return null;
}
if (levels.size() != getSize()) {
// do someting
}
// Time is always LINEAR
int inc = 0;
double[] vals = new double[getSize()];
String tstart = levels.get(0).trim().toLowerCase();
String pattern = null;
if (tstart.indexOf(":") >= 0) { // HH:mmZddMMMyyyy
pattern = dateFormats[0];
} else if (tstart.indexOf("z") >= 0) { // mmZddMMMyyyy
pattern = dateFormats[1];
} else if (Character.isLetter(tstart.charAt(0))) { // MMMyyyy
pattern = dateFormats[3];
} else {
pattern = dateFormats[2]; // ddMMMyyyy
}
SimpleDateFormat sdf = new SimpleDateFormat(pattern);
//sdf.setLenient(true);
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
ParsePosition p = new ParsePosition(0);
Date d = sdf.parse(tstart, p);
if (d == null) {
System.out.println("couldn't parse at " + p.getErrorIndex());
d = new Date(0);
}
//System.out.println("start = " + d);
// set the unit
sdf.applyPattern("yyyy-MM-dd HH:mm:ss Z");
setUnit("hours since "
+ sdf.format(d, new StringBuffer(), new FieldPosition(0)));
// parse the increment
// vvkk where
// vv = an integer number, 1 or 2 digits
// kk = mn (minute)
// hr (hour)
// dy (day)
// mo (month)
// yr (year)
String tinc = levels.get(1).toLowerCase();
int incIndex = 0;
for (int i = 0; i < incStr.length; i++) {
int index = tinc.indexOf(incStr[i]);
if (index < 0) {
continue;
}
int numOf = Integer.parseInt(tinc.substring(0, index));
inc = numOf;
incIndex = i;
break;
}
Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
calendar.setTime(d);
vals[0] = 0;
initialTime = makeTimeStruct(calendar);
//System.out.println("initial time = " + initialTime);
int calInc = calIncs[incIndex];
for (int i = 1; i < getSize(); i++) {
calendar.add(calInc, inc);
// subtract from origin, convert to hours
double offset = (calendar.getTime().getTime() - d.getTime())
/ (1000 * 60 * 60); //millis in an hour
vals[i] = offset;
}
return vals;
}
/**
* Make a time struct from the index.
*
* @param timeIndex the time value index
*
* @return the corresponding TimeStruct
*/
public GradsTimeStruct makeTimeStruct(int timeIndex) {
double tVal = getValues()[timeIndex];
Date d = DateUnit.getStandardDate(tVal + " " + getUnit());
Calendar calendar = Calendar.getInstance();
calendar.setTimeZone(java.util.TimeZone.getTimeZone("GMT"));
calendar.setTime(d);
return makeTimeStruct(calendar);
}
/**
* Make a GradsTimeStruct from the calendar state
*
* @param calendar the calendar
*
* @return the corresponding GradsTimeStruct
*/
private GradsTimeStruct makeTimeStruct(Calendar calendar) {
GradsTimeStruct ts = new GradsTimeStruct();
ts.year = calendar.get(Calendar.YEAR);
ts.month = calendar.get(Calendar.MONTH) + 1; // MONTH is zero based
ts.day = calendar.get(Calendar.DAY_OF_MONTH);
ts.hour = calendar.get(Calendar.HOUR_OF_DAY);
ts.minute = calendar.get(Calendar.MINUTE);
ts.jday = calendar.get(Calendar.DAY_OF_YEAR);
return ts;
}
/**
* Replace the time template parameters in a filename
*
* @param filespec the file template
* @param timeIndex the time index
*
* @see "http://www.iges.org/grads/gadoc/templates.html"
*
* @return the filled in template
*/
public String replaceFileTemplate(String filespec, int timeIndex) {
GradsTimeStruct ts = makeTimeStruct(timeIndex);
//System.out.println(ts);
String retString = filespec;
String format;
while (hasTimeTemplate(retString)) {
// initial time
if (retString.indexOf("%ix1") >= 0) {
retString = retString.replaceAll("%ix1",
String.format("%d", initialTime.year / 10));
}
if (retString.indexOf("%ix3") >= 0) {
retString = retString.replaceAll("%ix3",
String.format("%03d", initialTime.year / 10));
}
if (retString.indexOf("%iy2") >= 0) {
int cent = initialTime.year / 100;
int val = initialTime.year - cent * 100;
retString = retString.replaceAll("%iy2",
String.format("%02d", val));
}
if (retString.indexOf("%iy4") >= 0) {
retString = retString.replaceAll("%iy4",
String.format("%d", initialTime.year));
}
if (retString.indexOf("%im1") >= 0) {
retString = retString.replaceAll("%im1",
String.format("%d", initialTime.month));
}
if (retString.indexOf("%im2") >= 0) {
retString = retString.replaceAll("%im2",
String.format("%02d", initialTime.month));
}
if (retString.indexOf("%imc") >= 0) {
retString = retString.replaceAll("%imc",
GradsTimeStruct.months[initialTime.month - 1]);
}
if (retString.indexOf("%id1") >= 0) {
retString = retString.replaceAll("%id1",
String.format("%d", initialTime.day));
}
if (retString.indexOf("%id2") >= 0) {
retString = retString.replaceAll("%id2",
String.format("%02d", initialTime.day));
}
if (retString.indexOf("%ih1") >= 0) {
retString = retString.replaceAll("%ih1",
String.format("%d", initialTime.hour));
}
if (retString.indexOf("%ih2") >= 0) {
retString = retString.replaceAll("%ih2",
String.format("%02d", initialTime.hour));
}
if (retString.indexOf("%ih3") >= 0) {
retString = retString.replaceAll("%ih3",
String.format("%03d", initialTime.hour));
}
if (retString.indexOf("%in2") >= 0) {
retString = retString.replaceAll("%in2",
String.format("%02d", initialTime.minute));
}
// any time
// decade
if (retString.indexOf("%x1") >= 0) {
retString = retString.replaceAll("%x1",
String.format("%d", ts.year / 10));
}
if (retString.indexOf("%x3") >= 0) {
retString = retString.replaceAll("%x3",
String.format("%03d", ts.year / 10));
}
// year
if (retString.indexOf("%y2") >= 0) {
int cent = ts.year / 100;
int val = ts.year - cent * 100;
retString = retString.replaceAll("%y2",
String.format("%02d", val));
}
if (retString.indexOf("%y4") >= 0) {
retString = retString.replaceAll("%y4",
String.format("%d", ts.year));
}
// month
if (retString.indexOf("%m1") >= 0) {
retString = retString.replaceAll("%m1",
String.format("%d", ts.month));
}
if (retString.indexOf("%m2") >= 0) {
retString = retString.replaceAll("%m2",
String.format("%02d", ts.month));
}
if (retString.indexOf("%mc") >= 0) {
retString = retString.replaceAll("%mc",
GradsTimeStruct.months[ts.month - 1]);
}
// day
if (retString.indexOf("%d1") >= 0) {
retString = retString.replaceAll("%d1",
String.format("%d", ts.day));
}
if (retString.indexOf("%d2") >= 0) {
retString = retString.replaceAll("%d2",
String.format("%02d", ts.day));
}
// hour
if (retString.indexOf("%h1") >= 0) {
retString = retString.replaceAll("%h1",
String.format("%d", ts.hour));
}
if (retString.indexOf("%h2") >= 0) {
retString = retString.replaceAll("%h2",
String.format("%02d", ts.hour));
}
if (retString.indexOf("%h3") >= 0) {
retString = retString.replaceAll("%h3",
String.format("%03d", ts.hour));
}
// minute
if (retString.indexOf("%n2") >= 0) {
retString = retString.replaceAll("%n2",
String.format("%02d", ts.minute));
}
// julian day
if (retString.indexOf("%j3") >= 0) {
retString = retString.replaceAll("%j3",
String.format("%03d", ts.jday));
}
// time index (1 based)
if (retString.indexOf("%t1") >= 0) {
retString = retString.replaceAll("%t1",
String.format("%d", timeIndex + 1));
}
if (retString.indexOf("%t2") >= 0) {
retString = retString.replaceAll("%t2",
String.format("%02d", timeIndex + 1));
}
if (retString.indexOf("%t3") >= 0) {
retString = retString.replaceAll("%t3",
String.format("%03d", timeIndex + 1));
}
if (retString.indexOf("%t4") >= 0) {
retString = retString.replaceAll("%t4",
String.format("%04d", timeIndex + 1));
}
if (retString.indexOf("%t5") >= 0) {
retString = retString.replaceAll("%t5",
String.format("%05d", timeIndex + 1));
}
if (retString.indexOf("%t6") >= 0) {
retString = retString.replaceAll("%t6",
String.format("%06d", timeIndex + 1));
}
// time index (0 based)
if (retString.indexOf("%tm1") >= 0) {
retString = retString.replaceAll("%tm1",
String.format("%d", timeIndex));
}
if (retString.indexOf("%tm2") >= 0) {
retString = retString.replaceAll("%tm2",
String.format("%02d", timeIndex));
}
if (retString.indexOf("%tm3") >= 0) {
retString = retString.replaceAll("%tm3",
String.format("%03d", timeIndex));
}
if (retString.indexOf("%tm4") >= 0) {
retString = retString.replaceAll("%tm4",
String.format("%04d", timeIndex));
}
if (retString.indexOf("%tm5") >= 0) {
retString = retString.replaceAll("%tm5",
String.format("%05d", timeIndex));
}
if (retString.indexOf("%tm6") >= 0) {
retString = retString.replaceAll("%tm6",
String.format("%06d", timeIndex));
}
// forecast hours
if (retString.indexOf("%f") >= 0) {
int mins = (int) getValues()[timeIndex] * 60;
int tdif;
if (retString.indexOf("%f2") >= 0) {
format = "%02d";
tdif = mins / 60;
if (tdif > 99) {
format = "%d";
}
retString = retString.replaceAll("%f2",
String.format(format, tdif));
}
if (retString.indexOf("%f3") >= 0) {
format = "%03d";
tdif = mins / 60;
if (tdif > 999) {
format = "%d";
}
retString = retString.replaceAll("%f3",
String.format(format, tdif));
}
if (retString.indexOf("%fn2") >= 0) {
format = "%02d";
if (mins > 99) {
format = "%d";
}
retString = retString.replaceAll("%fn2",
String.format(format, mins));
}
if (retString.indexOf("%fhn2") >= 0) {
tdif = mins;
int hrs = tdif / 60;
int mns = tdif - (hrs * 60);
format = "%02d%02d";
if (hrs > 99) {
format = "%d%02d";
}
retString = retString.replaceAll("%fhn2",
String.format(format, hrs, mns));
}
if (retString.indexOf("%fdhn2") >= 0) {
tdif = mins;
int dys = tdif / 1440;
int hrs = (tdif - (dys * 1440)) / 60;
int mns = tdif - (dys * 1440) - (hrs * 60);
format = "%02d%02d%02d";
if (dys > 99) {
format = "%d%02d%02d";
}
retString = retString.replaceAll("%fdhn2",
String.format(format, dys, hrs, mns));
}
}
}
return retString;
}
/**
* Does this file definition have a time template in it?
* @param template the file template
* @return true if it does
*/
public static boolean hasTimeTemplate(String template) {
for (int i = 0; i < timeTemplates.length; i++) {
if (template.indexOf(timeTemplates[i]) >= 0) {
return true;
}
}
return false;
}
}