diff --git a/edexOsgi/com.raytheon.edex.plugin.airep/src/com/raytheon/edex/plugin/airep/AirepDecoder.java b/edexOsgi/com.raytheon.edex.plugin.airep/src/com/raytheon/edex/plugin/airep/AirepDecoder.java index 55a437cf96..13d59e3b43 100644 --- a/edexOsgi/com.raytheon.edex.plugin.airep/src/com/raytheon/edex/plugin/airep/AirepDecoder.java +++ b/edexOsgi/com.raytheon.edex.plugin.airep/src/com/raytheon/edex/plugin/airep/AirepDecoder.java @@ -22,6 +22,7 @@ package com.raytheon.edex.plugin.airep; import java.util.Calendar; import java.util.Map; +import com.raytheon.edex.esb.Headers; import com.raytheon.edex.exception.DecoderException; import com.raytheon.edex.plugin.AbstractDecoder; import com.raytheon.edex.plugin.airep.decoder.AIREPWeather; @@ -46,7 +47,7 @@ import com.raytheon.uf.edex.wmo.message.WMOHeader; * } * * - * + * *
  * 
  * SOFTWARE HISTORY
@@ -89,7 +90,7 @@ public class AirepDecoder extends AbstractDecoder {
      * @throws DecoderException
      *             Thrown if no data is available.
      */
-    public PluginDataObject[] decode(AirepDecoderInput input)
+    public PluginDataObject[] decode(AirepDecoderInput input, Headers header)
             throws DecoderException {
 
         PluginDataObject[] reports = null;
@@ -100,9 +101,14 @@ public class AirepDecoder extends AbstractDecoder {
         try {
             // traceId = getTraceId(hdrMap);
             logger.debug(traceId + "- AirepDecoder.decode()");
-
-            report = populateRecord(new AirepParser(input.report,
-                    input.wmoHeader), input.wmoHeader);
+            WMOHeader wmoHeader = input.wmoHeader;
+            if(wmoHeader != null) {
+                Calendar refTime = TimeTools.findDataTime(
+                        wmoHeader.getYYGGgg(), header);
+                if(refTime != null) {
+                    report = populateRecord(new AirepParser(input.report, refTime));
+                }
+            }
             if (report != null) {
                 report.setTraceId(traceId);
                 report.setPluginName(PLUGIN_NAME);
@@ -130,7 +136,7 @@ public class AirepDecoder extends AbstractDecoder {
      *            The reccon parser that contains the decoded data.
      * @return The populated record.
      */
-    private AirepRecord populateRecord(AirepParser parser, WMOHeader wmoHeader) {
+    private AirepRecord populateRecord(AirepParser parser) {
 
         AirepRecord record = null;
         AircraftObsLocation location = null;
diff --git a/edexOsgi/com.raytheon.edex.plugin.airep/src/com/raytheon/edex/plugin/airep/decoder/AirepParser.java b/edexOsgi/com.raytheon.edex.plugin.airep/src/com/raytheon/edex/plugin/airep/decoder/AirepParser.java
index 5a8eb16433..75d821cdb4 100644
--- a/edexOsgi/com.raytheon.edex.plugin.airep/src/com/raytheon/edex/plugin/airep/decoder/AirepParser.java
+++ b/edexOsgi/com.raytheon.edex.plugin.airep/src/com/raytheon/edex/plugin/airep/decoder/AirepParser.java
@@ -19,14 +19,17 @@
  **/
 package com.raytheon.edex.plugin.airep.decoder;
 
+import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.StringTokenizer;
+import java.util.TimeZone;
 import java.util.regex.Pattern;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
+import com.raytheon.edex.esb.Headers;
 import com.raytheon.uf.edex.decodertools.aircraft.AircraftFlightLevel;
 import com.raytheon.uf.edex.decodertools.aircraft.AircraftLatitude;
 import com.raytheon.uf.edex.decodertools.aircraft.AircraftLongitude;
@@ -121,7 +124,8 @@ public class AirepParser {
 
     private AircraftRemarks rptRemarks = null;
 
-    private WMOHeader wmoHeader;
+    private Calendar refTime;
+    
 
     /**
      * Create the parser for and decode an observation from a String.
@@ -129,21 +133,20 @@ public class AirepParser {
      * @param anObservation
      *            A string containing the observation.
      */
-    public AirepParser(String anObservation, WMOHeader wmoHeader) {
-        this.wmoHeader = wmoHeader;
+    public AirepParser(String anObservation, Calendar refTime) {
+        this.refTime = refTime;
         reportData = anObservation;
         parseElements();
     } // AirepParser()
 
     /**
-     * Create the parser for and decode an observation from a String.
+     * Create the parser for and decode an observation from a byte array.
      * 
      * @param anObservation
      *            A string containing the observation.
      */
-    public AirepParser(byte[] anObservation) {
-        reportData = new String(anObservation);
-        parseElements();
+    public AirepParser(byte[] anObservation, Calendar refTime) {
+        this(new String(anObservation), refTime);
     } // AirepParser()
 
     /**
@@ -263,11 +266,10 @@ public class AirepParser {
         for (int i = 0; i < theElements.size(); i++) {
             Object o = theElements.get(i);
             if (o instanceof String) {
-                String[] latLon = null; // AircraftLatitude.splitLatLon((String)
-                                        // o);
-                if (latLon != null) {
-                    theElements.set(i, latLon[1]);
+                String[] latLon = AircraftLatitude.splitLatLon((String) o);
+                if ((latLon != null)&&(latLon.length ==2)) {
                     theElements.add(i, latLon[0]);
+                    theElements.set(i, latLon[1]);
                     break;
                 }
             }
@@ -329,23 +331,25 @@ public class AirepParser {
             if (o instanceof String) {
                 String s = (String) o;
                 if (TIME.matcher(s).matches()) {
+
                     int hour = Integer.parseInt(s.substring(0, 2));
                     int minute = Integer.parseInt(s.substring(2));
-                    Calendar oTime = TimeTools.getSystemCalendar(
-                            wmoHeader.getYear(), wmoHeader.getMonth(),
-                            wmoHeader.getDay());
 
-                    observationTime = TimeTools.copy(oTime);
-                    observationTime.set(Calendar.HOUR_OF_DAY, hour);
-                    observationTime.set(Calendar.MINUTE, minute);
-                    observationTime.set(Calendar.SECOND, 0);
-                    observationTime.set(Calendar.MILLISECOND, 0);
+                    if (refTime != null) {
+                        
+                        observationTime = TimeTools.copy(refTime);
+                        observationTime.set(Calendar.HOUR_OF_DAY, hour);
+                        observationTime.set(Calendar.MINUTE, minute);
+                        observationTime.set(Calendar.SECOND, 0);
+                        observationTime.set(Calendar.MILLISECOND, 0);
+                        // If the observation time ends up greater than
+                        // the reference time, back up a day.
+                        if (observationTime.compareTo(refTime) > 0) {
+                            observationTime.add(Calendar.DAY_OF_MONTH, -1);
+                        }
 
-                    if (observationTime.compareTo(oTime) > 0) {
-                        observationTime.add(Calendar.DAY_OF_MONTH, -1);
+                        theElements.set(i, observationTime);
                     }
-
-                    theElements.set(i, observationTime);
                     break;
                 }
             }
@@ -679,4 +683,24 @@ public class AirepParser {
         return (rptRemarks != null) ? rptRemarks.toString() : "";
     } // getRemarks()
 
+    
+    public static void main(String [] args) {
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        sdf.setTimeZone(TimeZone.getTimeZone("ZULU"));
+        
+        Calendar refTime = TimeTools.getBaseCalendar(2011, 12, 14);
+        refTime.set(Calendar.HOUR_OF_DAY, 17);
+        refTime.set(Calendar.MINUTE, 15);
+        refTime.set(Calendar.SECOND, 00);
+        refTime.set(Calendar.MILLISECOND, 0);
+        
+        String data = "ARP UAL121 4400N 05700W 1640 F390 MS00 000/099KT TB MOD SK CLEAR=";
+        AirepParser p = new AirepParser(data,refTime);
+        System.out.println(sdf.format(p.getObservationTime().getTime()));
+        
+        data = "ARP UAL121 4400N 05700W 1840 F390 MS00 000/099KT TB MOD SK CLEAR=";
+        p = new AirepParser(data,refTime);
+        System.out.println(sdf.format(p.getObservationTime().getTime()));
+    }
+    
 } // AirepParser
diff --git a/edexOsgi/com.raytheon.edex.plugin.binlightning/src/com/raytheon/edex/plugin/binlightning/BinLightningDecoder.java b/edexOsgi/com.raytheon.edex.plugin.binlightning/src/com/raytheon/edex/plugin/binlightning/BinLightningDecoder.java
index 286f6b922f..31cca18e61 100644
--- a/edexOsgi/com.raytheon.edex.plugin.binlightning/src/com/raytheon/edex/plugin/binlightning/BinLightningDecoder.java
+++ b/edexOsgi/com.raytheon.edex.plugin.binlightning/src/com/raytheon/edex/plugin/binlightning/BinLightningDecoder.java
@@ -92,6 +92,8 @@ public class BinLightningDecoder extends AbstractDecoder {
     // Allow ingest up to 10 minutes into the future.
     private static final long TEN_MINUTES = 10 * 60 * 1000L;
 
+    private SimpleDateFormat SDF; 
+    
     private Log logger = LogFactory.getLog(getClass());
 
     /**
@@ -107,6 +109,8 @@ public class BinLightningDecoder extends AbstractDecoder {
      * will return false, decode() will return a null.
      */
     public BinLightningDecoder() {
+        SDF = new SimpleDateFormat("yyyyMMddHHmmss");
+        SDF.setTimeZone(TimeZone.getTimeZone("Zulu"));
     }
 
     /**
@@ -119,14 +123,20 @@ public class BinLightningDecoder extends AbstractDecoder {
     public PluginDataObject[] decode(byte[] data, Headers headers)
             throws DecoderException {
 
+        
+        
         String traceId = null;
         PluginDataObject[] reports = new PluginDataObject[0];
         if (data != null) {
 
             traceId = (String) headers.get(DecoderTools.INGEST_FILE_NAME);
 
-            WMOHeader header = new WMOHeader(data);
-            if (header.isValid()) {
+            WMOHeader wmoHdr = new WMOHeader(data);
+            if (wmoHdr.isValid()) {
+
+                Calendar baseTime = TimeTools.findDataTime(wmoHdr.getYYGGgg(), headers);
+                
+                
                 byte[] pdata = DecoderTools.stripWMOHeader(data, SFUS_PATTERN);
                 if (pdata == null) {
                     pdata = DecoderTools.stripWMOHeader(data, SFPA_PATTERN);
@@ -174,7 +184,7 @@ public class BinLightningDecoder extends AbstractDecoder {
                         return new PluginDataObject[0];
                     }
 
-                    Calendar c = TimeTools.getSystemCalendar();
+                    Calendar c = TimeTools.copy(baseTime);
                     if (c == null) {
                         throw new DecoderException(traceId
                                 + "-Error decoding times");
@@ -184,11 +194,10 @@ public class BinLightningDecoder extends AbstractDecoder {
                     Calendar cStart = report.getStartTime();
                     if (cStart.getTimeInMillis() > c.getTimeInMillis()
                             + TEN_MINUTES) {
-                        SimpleDateFormat sdf = new SimpleDateFormat(
-                                "yyyyMMddHHmmss");
-                        sdf.setTimeZone(TimeZone.getTimeZone("Zulu"));
-                        logger.info("Discarding future data for " + traceId
-                                + " at " + sdf.format(cStart.getTime()));
+                        synchronized(SDF) {
+                            logger.info("Discarding future data for " + traceId
+                                    + " at " + SDF.format(cStart.getTime()));
+                        }
                     } else {
                         Calendar cStop = report.getStopTime();
 
@@ -206,8 +215,7 @@ public class BinLightningDecoder extends AbstractDecoder {
                                 report.constructDataURI();
                                 reports = new PluginDataObject[] { report };
                             } catch (PluginException e) {
-                                throw new DecoderException(
-                                        "Error constructing datauri", e);
+                                logger.error("Error constructing datauri", e);
                             }
                         }
                     }
diff --git a/edexOsgi/com.raytheon.edex.plugin.ccfp/src/com/raytheon/edex/plugin/ccfp/CcfpDecoder.java b/edexOsgi/com.raytheon.edex.plugin.ccfp/src/com/raytheon/edex/plugin/ccfp/CcfpDecoder.java
index 5ec3c809ec..8ff32691fb 100644
--- a/edexOsgi/com.raytheon.edex.plugin.ccfp/src/com/raytheon/edex/plugin/ccfp/CcfpDecoder.java
+++ b/edexOsgi/com.raytheon.edex.plugin.ccfp/src/com/raytheon/edex/plugin/ccfp/CcfpDecoder.java
@@ -24,6 +24,7 @@ import java.util.Calendar;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
+import com.raytheon.edex.esb.Headers;
 import com.raytheon.edex.exception.DecoderException;
 import com.raytheon.edex.plugin.AbstractDecoder;
 import com.raytheon.uf.common.dataplugin.PluginDataObject;
@@ -31,6 +32,7 @@ import com.raytheon.uf.common.dataplugin.PluginException;
 import com.raytheon.uf.common.time.DataTime;
 import com.raytheon.uf.common.time.TimeRange;
 import com.raytheon.uf.edex.decodertools.time.TimeTools;
+import com.raytheon.uf.edex.wmo.message.WMOHeader;
 import com.vividsolutions.jts.io.WKTReader;
 
 /**
@@ -84,6 +86,7 @@ public class CcfpDecoder extends AbstractDecoder {
 
     private static final String SPACE = " ";
 
+    private static final PluginDataObject [] EMPTY_PDO = new PluginDataObject [0];
     /**
      * Constructor
      * 
@@ -92,9 +95,18 @@ public class CcfpDecoder extends AbstractDecoder {
     public CcfpDecoder() throws DecoderException {
     }
 
-    public PluginDataObject[] decode(String msg) throws DecoderException,
-            PluginException {
+    public PluginDataObject[] decode(String msg, Headers headers) throws PluginException {
 
+        PluginDataObject [] data = null;
+        
+        Calendar baseTime = null;
+        WMOHeader wmoHdr = new WMOHeader(msg.getBytes());
+        if (wmoHdr.isValid()) {
+            baseTime = TimeTools.findDataTime(wmoHdr.getYYGGgg(), headers);
+        } else {
+            baseTime = TimeTools.getSystemCalendar();
+        }
+        
         CcfpRecord record = new CcfpRecord();
         record.setMessageData(msg);
         CcfpLocation location = new CcfpLocation();
@@ -124,7 +136,7 @@ public class CcfpDecoder extends AbstractDecoder {
                 } else {
                     record.setCanadaflag(Boolean.FALSE);
                 }
-                record.setInsertTime(TimeTools.getSystemCalendar());
+                record.setInsertTime(baseTime);
             }
             if (record.getProducttype().equals("AREA")) {
                 matcher = AREA_PATTERN.matcher(msg);
@@ -205,15 +217,20 @@ public class CcfpDecoder extends AbstractDecoder {
                 }
             }
         } catch (Exception e) {
-            throw new DecoderException("Unable to decode CCFP", e);
+            record = null;
+            logger.error("Unable to decode CCFP", e);
         }
-        if (record != null) {
+        data = EMPTY_PDO;
+        if(record != null) {
             record.setPluginName(PLUGIN_NAME);
-            record.constructDataURI();
-            return new PluginDataObject[] { record };
-        } else {
-            return new PluginDataObject[0];
+            try {
+                record.constructDataURI();
+                record.setInsertTime(baseTime);
+                data = new PluginDataObject[] { record };
+            } catch (PluginException e) {
+                logger.error("Error constructing datauri", e);
+            }
         }
-
+        return data;
     }
 }
diff --git a/edexOsgi/com.raytheon.edex.plugin.goessounding/src/com/raytheon/edex/plugin/goessounding/GOESSoundingDecoder.java b/edexOsgi/com.raytheon.edex.plugin.goessounding/src/com/raytheon/edex/plugin/goessounding/GOESSoundingDecoder.java
index 973f058c84..d3e820e96f 100644
--- a/edexOsgi/com.raytheon.edex.plugin.goessounding/src/com/raytheon/edex/plugin/goessounding/GOESSoundingDecoder.java
+++ b/edexOsgi/com.raytheon.edex.plugin.goessounding/src/com/raytheon/edex/plugin/goessounding/GOESSoundingDecoder.java
@@ -136,7 +136,6 @@ public class GOESSoundingDecoder extends AbstractDecoder implements
             WMOHeader wmoHeader = input.getWmoHeader();
 
             if ((wmoHeader != null) && (wmoHeader.isValid())) {
-
                 try {
                     byte[] messageData = input.getDocumentData();
 
diff --git a/edexOsgi/com.raytheon.edex.plugin.goessounding/src/com/raytheon/edex/plugin/goessounding/decoder/GOESSoundingDataAdapter.java b/edexOsgi/com.raytheon.edex.plugin.goessounding/src/com/raytheon/edex/plugin/goessounding/decoder/GOESSoundingDataAdapter.java
index 4c8fc28261..81a6b1e2d5 100644
--- a/edexOsgi/com.raytheon.edex.plugin.goessounding/src/com/raytheon/edex/plugin/goessounding/decoder/GOESSoundingDataAdapter.java
+++ b/edexOsgi/com.raytheon.edex.plugin.goessounding/src/com/raytheon/edex/plugin/goessounding/decoder/GOESSoundingDataAdapter.java
@@ -211,8 +211,7 @@ public class GOESSoundingDataAdapter {
 //                seconds = (dp.getValue() != null) ? ((Double) dp.getValue())
 //                        .intValue() : null;
 
-                Calendar baseTime = TimeTools.getSystemCalendar();
-                baseTime.set(Calendar.YEAR, year);
+                Calendar baseTime = TimeTools.getBaseCalendar(year, 1, 1);
                 baseTime.set(Calendar.DAY_OF_YEAR, day);
                 baseTime.set(Calendar.HOUR_OF_DAY, hour);
                 baseTime.set(Calendar.MINUTE, minute);
diff --git a/edexOsgi/com.raytheon.edex.plugin.obs/src/com/raytheon/edex/plugin/obs/metar/MetarDecoder.java b/edexOsgi/com.raytheon.edex.plugin.obs/src/com/raytheon/edex/plugin/obs/metar/MetarDecoder.java
index 634ec53756..5d0a18cef7 100644
--- a/edexOsgi/com.raytheon.edex.plugin.obs/src/com/raytheon/edex/plugin/obs/metar/MetarDecoder.java
+++ b/edexOsgi/com.raytheon.edex.plugin.obs/src/com/raytheon/edex/plugin/obs/metar/MetarDecoder.java
@@ -42,6 +42,7 @@ import com.raytheon.uf.common.time.DataTime;
 import com.raytheon.uf.edex.decodertools.core.DecoderTools;
 import com.raytheon.uf.edex.decodertools.core.IDecoderConstants;
 import com.raytheon.uf.edex.decodertools.time.TimeTools;
+import com.raytheon.uf.edex.wmo.message.WMOHeader;
 import com.vividsolutions.jts.geom.Coordinate;
 import com.vividsolutions.jts.geom.GeometryFactory;
 import com.vividsolutions.jts.geom.Point;
@@ -210,8 +211,22 @@ public class MetarDecoder extends AbstractDecoder {
             throws DecoderException {
 
         MetarSeparator sep = MetarSeparator.separate(inputData, headers);
+        
         List retVal = new ArrayList();
 
+//        String fileName = null;
+//        if (headers != null) {
+//            fileName = (String) headers
+//                    .get(DecoderTools.INGEST_FILE_NAME);
+//        }
+        Calendar baseTime;
+        WMOHeader wmoHdr = sep.getWMOHeader();
+        if((wmoHdr != null)&&(wmoHdr.isValid())) {
+            baseTime = TimeTools.findDataTime(wmoHdr.getYYGGgg(), headers);
+        } else {
+            baseTime = TimeTools.getSystemCalendar();
+        }
+        
         while (sep.hasNext()) {
             byte[] messageData = sep.next();
             Pattern thePattern;
@@ -278,17 +293,26 @@ public class MetarDecoder extends AbstractDecoder {
                                         traceId, icao));
                         continue;
                     }
-                    String fileName = null;
-                    if (headers != null) {
-                        fileName = (String) headers
-                                .get(DecoderTools.INGEST_FILE_NAME);
-                    }
-                    Calendar obsTime = TimeTools.findCurrentTime(
-                            matcher.group(3), fileName);
+                    
+                    
+                    Calendar obsTime = null;
+                    Integer da = DecoderTools.getInt(timeGroup, 0, 2);
+                    Integer hr = DecoderTools.getInt(timeGroup, 2, 4);
+                    Integer mi = DecoderTools.getInt(timeGroup, 4, 6);
+                    if ((da != null) && (hr != null) && (mi != null)) {
+                        obsTime = TimeTools.copy(baseTime);
+                        obsTime.set(Calendar.DAY_OF_MONTH, da);
+                        obsTime.set(Calendar.HOUR_OF_DAY, hr);
+                        obsTime.set(Calendar.MINUTE, mi);
+                    }                    
                     if (obsTime != null) {
                         record.setTimeObs(obsTime);
                         record.setDataTime(new DataTime(obsTime));
-                        record.setRefHour(Util.findReferenceHour(timeGroup));
+                        Calendar refHour = TimeTools.copyToNearestHour(obsTime);
+                        if(mi >= 45) {
+                            refHour.add(Calendar.HOUR_OF_DAY, 1);
+                        }
+                        record.setRefHour(refHour);
                         // TODO :
                     } else {
                         // couldn't find observation time so exit.
@@ -301,7 +325,7 @@ public class MetarDecoder extends AbstractDecoder {
                 // into the future
                 Calendar obsTime = record.getTimeObs();
                 if (obsTime != null) {
-                    Calendar currTime = TimeTools.getSystemCalendar();
+                    Calendar currTime = TimeTools.copy(baseTime);
                     currTime.add(Calendar.MINUTE, METAR_FUTURE_LIMIT);
 
                     long diff = currTime.getTimeInMillis()
diff --git a/edexOsgi/com.raytheon.edex.plugin.obs/src/com/raytheon/edex/plugin/obs/metar/MetarPointDataTransform.java b/edexOsgi/com.raytheon.edex.plugin.obs/src/com/raytheon/edex/plugin/obs/metar/MetarPointDataTransform.java
index 36b63edda6..4c24c81150 100644
--- a/edexOsgi/com.raytheon.edex.plugin.obs/src/com/raytheon/edex/plugin/obs/metar/MetarPointDataTransform.java
+++ b/edexOsgi/com.raytheon.edex.plugin.obs/src/com/raytheon/edex/plugin/obs/metar/MetarPointDataTransform.java
@@ -456,9 +456,7 @@ public class MetarPointDataTransform {
         mr.setPkWndSpd(pdv.getNumber(PK_WND_SPD).intValue());
         long t = pdv.getNumber(PK_WND_TIME).longValue();
         if (t >= 0) {
-            Calendar c = TimeTools.getSystemCalendar();
-            c.setTimeInMillis(t);
-            mr.setPkWndTime(c);
+            mr.setPkWndTime(TimeTools.newCalendar(t));
         }
 
         return mr;
diff --git a/edexOsgi/com.raytheon.edex.plugin.shef/src/com/raytheon/edex/plugin/shef/ShefDecoder.java b/edexOsgi/com.raytheon.edex.plugin.shef/src/com/raytheon/edex/plugin/shef/ShefDecoder.java
index f56e5a576d..7c1cf02bcd 100644
--- a/edexOsgi/com.raytheon.edex.plugin.shef/src/com/raytheon/edex/plugin/shef/ShefDecoder.java
+++ b/edexOsgi/com.raytheon.edex.plugin.shef/src/com/raytheon/edex/plugin/shef/ShefDecoder.java
@@ -19,7 +19,6 @@
  **/
 package com.raytheon.edex.plugin.shef;
 
-import java.util.Calendar;
 import java.util.Date;
 
 import org.apache.commons.logging.Log;
@@ -34,7 +33,6 @@ import com.raytheon.edex.plugin.shef.database.PurgeText;
 import com.raytheon.uf.common.dataplugin.PluginDataObject;
 import com.raytheon.uf.common.ohd.AppsDefaults;
 import com.raytheon.uf.edex.decodertools.core.DecoderTools;
-import com.raytheon.uf.edex.wmo.message.WMOHeader;
 
 /**
  * Decoder implementation for SHEF data
@@ -91,6 +89,8 @@ public class ShefDecoder {
      * @return
      */
     public PluginDataObject[] decode(byte[] data, Headers headers) {
+        boolean archiveMode = AppsDefaults.getInstance().getBoolean("ALLOW_ARCHIVE_DATA",false);
+        
         String traceId = null;
 
         if (headers != null) {
@@ -108,8 +108,15 @@ public class ShefDecoder {
             separator = null;
         }
         if (separator != null) {
+            
             long startTime = System.currentTimeMillis();
-            Date postDate = getPostTime(startTime);
+
+            Date postDate = null;
+            if(archiveMode) {
+                postDate = getPostTime(separator.getWmoHeader().getHeaderDate().getTimeInMillis());
+            } else {
+                postDate = getPostTime(startTime);
+            }
 
             PostShef postShef = new PostShef(postDate);
             if(separator.hasNext()) {
@@ -181,10 +188,6 @@ public class ShefDecoder {
     private void doDecode(ShefSeparator separator, String traceId, PostShef postShef) {
         
         long startTime = System.currentTimeMillis();
-        long endTime;
-        
-        // Force time to nearest second.
-        long t = startTime - (startTime % 1000);
 
         AppsDefaults appDefaults = AppsDefaults.getInstance();
         boolean logSHEFOut = appDefaults.getBoolean("shef_out", false);
@@ -226,8 +229,7 @@ public class ShefDecoder {
             }
         } // while()
         if(dataProcessed) {
-            endTime = System.currentTimeMillis();
-            postShef.logStats(traceId, endTime - startTime);
+            postShef.logStats(traceId, System.currentTimeMillis() - startTime);
         }
     }
     
@@ -236,14 +238,15 @@ public class ShefDecoder {
      * @param startTime
      * @return
      */
-    private Date getPostTime(long startTime) {
+    private static Date getPostTime(long startTime) {
         // Force time to nearest second.
-        long t = startTime - (startTime % 1000);
-        return new Date(t);
+        return new Date(startTime - (startTime % 1000));
     }
     
     
-    
+    /*
+     * 
+     */
     public static final void main(String [] args) {
         
         long t = System.currentTimeMillis();
diff --git a/edexOsgi/com.raytheon.edex.plugin.shef/src/com/raytheon/edex/plugin/shef/ShefSeparator.java b/edexOsgi/com.raytheon.edex.plugin.shef/src/com/raytheon/edex/plugin/shef/ShefSeparator.java
index 816d579e87..96fac74867 100644
--- a/edexOsgi/com.raytheon.edex.plugin.shef/src/com/raytheon/edex/plugin/shef/ShefSeparator.java
+++ b/edexOsgi/com.raytheon.edex.plugin.shef/src/com/raytheon/edex/plugin/shef/ShefSeparator.java
@@ -162,6 +162,7 @@ public class ShefSeparator extends AbstractRecordSeparator {
                     traceId = wmoHeader.getWmoHeader();
                     log.info("TraceId set to WMOHeader = " + traceId);
                 }
+                // TODO: DR 14 - Shef time changes.
                 Calendar c = wmoHeader.getHeaderDate();
                 if (c != null) {
                     productTime = c.getTime();
diff --git a/edexOsgi/com.raytheon.edex.plugin.shef/src/com/raytheon/edex/plugin/shef/dao/ShefDao.java b/edexOsgi/com.raytheon.edex.plugin.shef/src/com/raytheon/edex/plugin/shef/dao/ShefDao.java
index 745b9422f8..e7ec037961 100644
--- a/edexOsgi/com.raytheon.edex.plugin.shef/src/com/raytheon/edex/plugin/shef/dao/ShefDao.java
+++ b/edexOsgi/com.raytheon.edex.plugin.shef/src/com/raytheon/edex/plugin/shef/dao/ShefDao.java
@@ -27,15 +27,13 @@ import com.raytheon.uf.common.ohd.AppsDefaults;
 
 public class ShefDao extends DefaultPluginDao {
 
-
-    private AppsDefaults appsDefaults;
-
-
-
-
+    /**
+     * 
+     * @param pluginName
+     * @throws PluginException
+     */
     public ShefDao(String pluginName) throws PluginException {
         super(pluginName);
-        appsDefaults = AppsDefaults.getInstance();
     }
 
     @Override
@@ -50,7 +48,7 @@ public class ShefDao extends DefaultPluginDao {
          * Purge the file system
          */
         logger.info("Purging Hydro file system...");
-        File metarInputFile = new File(appsDefaults
+        File metarInputFile = new File(AppsDefaults.getInstance()
                 .getToken("whfs_local_data_dir")
                 + "/metar_input");
         if (!metarInputFile.exists()) {
diff --git a/edexOsgi/com.raytheon.edex.plugin.shef/src/com/raytheon/edex/plugin/shef/database/PostShef.java b/edexOsgi/com.raytheon.edex.plugin.shef/src/com/raytheon/edex/plugin/shef/database/PostShef.java
index 60e5252cb2..21864e1b6f 100644
--- a/edexOsgi/com.raytheon.edex.plugin.shef/src/com/raytheon/edex/plugin/shef/database/PostShef.java
+++ b/edexOsgi/com.raytheon.edex.plugin.shef/src/com/raytheon/edex/plugin/shef/database/PostShef.java
@@ -25,7 +25,6 @@ import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.Date;
-import java.util.GregorianCalendar;
 import java.util.HashMap;
 import java.util.List;
 import java.util.TimeZone;
@@ -37,6 +36,12 @@ import org.apache.commons.logging.LogFactory;
 
 import com.raytheon.edex.plugin.shef.data.ShefData;
 import com.raytheon.edex.plugin.shef.data.ShefRecord;
+import com.raytheon.edex.plugin.shef.util.BitUtils;
+import com.raytheon.edex.plugin.shef.util.SHEFDate;
+import com.raytheon.edex.plugin.shef.util.ShefStats;
+import com.raytheon.edex.plugin.shef.util.ShefUtil;
+import com.raytheon.edex.plugin.shef.util.StoreDisposition;
+import com.raytheon.uf.common.dataplugin.persist.PersistableDataObject;
 import com.raytheon.uf.common.dataplugin.shef.tables.Alertalarmval;
 import com.raytheon.uf.common.dataplugin.shef.tables.AlertalarmvalId;
 import com.raytheon.uf.common.dataplugin.shef.tables.Arealfcst;
@@ -61,24 +66,17 @@ import com.raytheon.uf.common.dataplugin.shef.tables.Stnclass;
 import com.raytheon.uf.common.dataplugin.shef.tables.Unkstn;
 import com.raytheon.uf.common.dataplugin.shef.tables.Unkstnvalue;
 import com.raytheon.uf.common.dataplugin.shef.tables.UnkstnvalueId;
-
-import com.raytheon.edex.plugin.shef.util.BitUtils;
+import com.raytheon.uf.common.dataplugin.shef.util.ParameterCode;
 import com.raytheon.uf.common.dataplugin.shef.util.ParameterCode.DataType;
 import com.raytheon.uf.common.dataplugin.shef.util.ParameterCode.Duration;
 import com.raytheon.uf.common.dataplugin.shef.util.ParameterCode.Extremum;
 import com.raytheon.uf.common.dataplugin.shef.util.ParameterCode.PhysicalElement;
 import com.raytheon.uf.common.dataplugin.shef.util.ParameterCode.PhysicalElementCategory;
 import com.raytheon.uf.common.dataplugin.shef.util.ParameterCode.TypeSource;
-import com.raytheon.uf.common.dataplugin.shef.util.ParameterCode;
 import com.raytheon.uf.common.dataplugin.shef.util.SHEFTimezone;
-import com.raytheon.edex.plugin.shef.util.SHEFDate;
-import com.raytheon.edex.plugin.shef.util.ShefStats;
-import com.raytheon.edex.plugin.shef.util.ShefUtil;
-import com.raytheon.edex.plugin.shef.util.StoreDisposition;
-import com.raytheon.uf.common.dataplugin.persist.PersistableDataObject;
 import com.raytheon.uf.common.dataplugin.shef.util.ShefConstants;
-import com.raytheon.uf.common.dataplugin.shef.util.ShefQC;
 import com.raytheon.uf.common.dataplugin.shef.util.ShefConstants.IngestSwitch;
+import com.raytheon.uf.common.dataplugin.shef.util.ShefQC;
 import com.raytheon.uf.common.ohd.AppsDefaults;
 import com.raytheon.uf.edex.database.dao.CoreDao;
 import com.raytheon.uf.edex.database.dao.DaoConfig;
@@ -130,6 +128,11 @@ public class PostShef {
         QC_DEFAULT, QC_GROSSRANGE_FAILED, QC_REASONRANGE_FAILED, QC_ROC_FAILED, QC_ROC_PASSED, QC_OUTLIER_FAILED, QC_OUTLIER_PASSED, QC_SCC_FAILED, QC_SCC_PASSED, QC_MSC_FAILED, QC_MSC_PASSED, QC_EXTERN_FAILED, QC_EXTERN_QUEST, QC_MANUAL_PASSED, QC_MANUAL_QUEST, QC_MANUAL_FAILED, QC_MANUAL_NEW, QC_PASSED, QC_QUESTIONABLE, QC_FAILED, QC_NOT_PASSED, QC_NOT_FAILED
     };
 
+    private static final SimpleDateFormat DB_TIMESTAMP = new SimpleDateFormat(ShefConstants.POSTGRES_DATE_FORMAT.toPattern());
+    static {
+        DB_TIMESTAMP.setTimeZone(TimeZone.getTimeZone(ShefConstants.GMT));
+    }
+    
     private static final Pattern Q_CODES = Pattern.compile("Q[^BEF]");
     
     private static final String POST_START_MSG = "Posting process started for LID [%s] PEDTSEP [%s] value [%s]";
@@ -203,6 +206,8 @@ public class PostShef {
 
     private boolean perfLog = false;
 
+    private boolean archiveMode = false;
+    
     private HashMap idLocations = new HashMap();
 
     /**
@@ -256,6 +261,8 @@ public class PostShef {
         dataLog = appDefaults.getBoolean(ShefConstants.SHEF_DATA_LOG, false);
         // TODO need to implement this token and the performance logging
         perfLog = appDefaults.getBoolean(ShefConstants.SHEF_PERFLOG, false);
+        
+        archiveMode = appDefaults.getBoolean("ALLOW_ARCHIVE_DATA",false);
     }
 
     /**
@@ -652,7 +659,7 @@ public class PostShef {
                 start = System.currentTimeMillis();
                 // Identifier has been set from the awipsHeader.
 
-                postProductLink(locId, identifier, obsTime, postDate);
+                postProductLink(locId, identifier, obsTime);
                 // postProductLink(locId, shefRecord.getIdentifier(), obsTime);
                 stats.addElapsedTimeIngest(System.currentTimeMillis() - start);
                 
@@ -1112,9 +1119,13 @@ public class PostShef {
         String pe = null;
         String ts = null;
 
-        String query = "select lid,pe,ts " + "from " + tableName + " "
-                + "where validtime > CURRENT_TIMESTAMP and "
-                + "probability < 0.0";
+//      String query = "select lid,pe,ts " + "from " + tableName + " "
+//      + "where validtime > CURRENT_TIMESTAMP and "
+//      + "probability < 0.0";
+        
+        String query = String
+                .format("select lid,pe,ts from %s where validtime > '%s' and probability < 0.0",
+                        tableName, toTimeStamp(postDate));
 
         try {
             dao = new CoreDao(DaoConfig.forDatabase(ShefConstants.IHFS));
@@ -2553,8 +2564,7 @@ public class PostShef {
      * @param obsTime
      *            - The observation time
      */
-    private void postProductLink(String locId, String productId, Date obsTime,
-            Date postDate) {
+    private void postProductLink(String locId, String productId, Date obsTime) {
         if (log.isDebugEnabled()) {
             log.debug("PostShef.postProductLink() called...");
         }
@@ -3008,8 +3018,6 @@ public class PostShef {
                 basisTime = new Date();
             }
 
-            // TODO fix the duplicate code below:
-
             if (dataValue == "") {
                 dataValue = "-9999";
             }
@@ -3251,6 +3259,29 @@ public class PostShef {
         return dataObj;
     }
 
+    
+    /**
+     * 
+     * @param c
+     * @return
+     */
+    private static String toTimeStamp(Date d) {
+        String timeStamp = null;
+        if(d != null) {
+            timeStamp = DB_TIMESTAMP.format(d);
+        }
+        return timeStamp;
+    }
+
+    /**
+     * 
+     * @param c
+     * @return
+     */
+    private static String toTimeStamp(Calendar c) {
+        return toTimeStamp(c.getTime());
+    }
+    
     public static final void main(String[] args) {
 
         Calendar postDate = TimeTools.getBaseCalendar(2011, 1, 12);
diff --git a/edexOsgi/com.raytheon.edex.plugin.shef/src/com/raytheon/edex/plugin/shef/database/PostTables.java b/edexOsgi/com.raytheon.edex.plugin.shef/src/com/raytheon/edex/plugin/shef/database/PostTables.java
index 1dffcdcddf..8e8dde4de2 100644
--- a/edexOsgi/com.raytheon.edex.plugin.shef/src/com/raytheon/edex/plugin/shef/database/PostTables.java
+++ b/edexOsgi/com.raytheon.edex.plugin.shef/src/com/raytheon/edex/plugin/shef/database/PostTables.java
@@ -28,7 +28,8 @@ import java.util.List;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-import org.hibernate.Session;
+import org.hibernate.connection.ConnectionProvider;
+import org.hibernate.engine.SessionFactoryImplementor;
 
 import com.raytheon.edex.plugin.shef.data.ShefData;
 import com.raytheon.edex.plugin.shef.data.ShefRecord;
@@ -1036,15 +1037,16 @@ public class PostTables {
         CoreDao dao = null;
         Connection conn = null;
         CallableStatement cs = null;
-        Session ses = null;
         int status = -1;
         if (dataValue == "") {
             dataValue = ShefConstants.SHEF_MISSING;
         }
         try {
             dao = new CoreDao(DaoConfig.forDatabase(ShefConstants.IHFS));
-            ses = dao.getSessionFactory().openSession();
-            conn = ses.connection();
+            SessionFactoryImplementor impl = (SessionFactoryImplementor) dao.getSessionFactory();
+            ConnectionProvider cp = impl.getConnectionProvider();
+            conn = cp.getConnection();
+
             cs = conn.prepareCall("{call " + functionName
                     + "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)}");
             cs.setString(1, locId);
@@ -1128,14 +1130,8 @@ public class PostTables {
             } catch (Exception e) {
                 // Intentionally empty
             }
-            try {
-                ses.close();
-            } catch (Exception e) {
-                // Intentionally empty
-            }
             cs = null;
             conn = null;
-            ses = null;
         }
         return status;
     }
@@ -1159,7 +1155,6 @@ public class PostTables {
         }
         CoreDao dao = null;
         Connection conn = null;
-        Session ses = null;
         CallableStatement cs = null;
         int status = -1;
         if (dataValue == "") {
@@ -1167,8 +1162,10 @@ public class PostTables {
         }
         try {
             dao = new CoreDao(DaoConfig.forDatabase(ShefConstants.IHFS));
-            ses = dao.getSessionFactory().openSession();
-            conn = ses.connection();
+            SessionFactoryImplementor impl = (SessionFactoryImplementor) dao.getSessionFactory();
+            ConnectionProvider cp = impl.getConnectionProvider();
+            conn = cp.getConnection();
+
             cs = conn.prepareCall("{call " + functionName
                     + "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)}");
             cs.setString(1, locId);
@@ -1258,11 +1255,6 @@ public class PostTables {
             } catch (Exception e) {
                 // Intentionally empty
             }
-            try {
-                ses.close();
-            } catch (Exception e) {
-                // Intentionally empty
-            }
             cs = null;
             conn = null;
         }
@@ -1286,7 +1278,6 @@ public class PostTables {
         long start = System.currentTimeMillis();
         CoreDao dao = null;
         Connection conn = null;
-        Session ses = null;
         CallableStatement cs = null;
         java.sql.Timestamp timeStamp = null;
         int status = -1;
@@ -1296,8 +1287,10 @@ public class PostTables {
 
         try {
             dao = new CoreDao(DaoConfig.forDatabase(ShefConstants.IHFS));
-            ses = dao.getSessionFactory().openSession();
-            conn = ses.connection();
+            SessionFactoryImplementor impl = (SessionFactoryImplementor) dao.getSessionFactory();
+            ConnectionProvider cp = impl.getConnectionProvider();
+            conn = cp.getConnection();
+            
             cs = conn.prepareCall("{call " + functionName
                     + "(?, ?, ?, ?, ?, cast(? as real), ?, ?, ?, ?,"
                     + " ?, ?, ?, ?, ?, ?, ?)}");
@@ -1420,11 +1413,6 @@ public class PostTables {
             } catch (Exception e) {
                 // Intentionally empty
             }
-            try {
-                ses.close();
-            } catch (Exception e) {
-                // Intentionally empty
-            }
             cs = null;
             conn = null;
         }
@@ -1489,7 +1477,6 @@ public class PostTables {
 
         CoreDao dao = null;
         Connection conn = null;
-        Session ses = null;
         PreparedStatement ps = null;
         java.sql.Timestamp timeStamp = null;
         java.sql.Timestamp timeStamp2 = null;
@@ -1507,8 +1494,12 @@ public class PostTables {
 
         try {
             dao = new CoreDao(DaoConfig.forDatabase(ShefConstants.IHFS));
-            ses = dao.getSessionFactory().openSession();
-            conn = ses.connection();
+
+            SessionFactoryImplementor impl = (SessionFactoryImplementor) dao.getSessionFactory();
+            ConnectionProvider cp = impl.getConnectionProvider();
+
+            conn = cp.getConnection();
+            
             if (updateFlag) {
                 ps = conn.prepareCall(updateQuery);
             } else {
@@ -1617,11 +1608,6 @@ public class PostTables {
             } catch (Exception e) {
                 // Intentionally empty
             }
-            try {
-                ses.close();
-            } catch (Exception e) {
-                // Intentionally empty
-            }
             ps = null;
             conn = null;
         }
diff --git a/edexOsgi/com.raytheon.edex.plugin.shef/src/com/raytheon/edex/plugin/shef/ohdlib/GagePP.java b/edexOsgi/com.raytheon.edex.plugin.shef/src/com/raytheon/edex/plugin/shef/ohdlib/GagePP.java
index 75a2390387..e2bd6aaabf 100644
--- a/edexOsgi/com.raytheon.edex.plugin.shef/src/com/raytheon/edex/plugin/shef/ohdlib/GagePP.java
+++ b/edexOsgi/com.raytheon.edex.plugin.shef/src/com/raytheon/edex/plugin/shef/ohdlib/GagePP.java
@@ -89,8 +89,6 @@ public class GagePP {
 
     private static Log logger = LogFactory.getLog(GagePP.class);
 
-    private SimpleDateFormat minSDF = new SimpleDateFormat("mm");
-
     private GagePPWrite gagePPWrite = null;
 
     private char pOffsetCode;
@@ -100,10 +98,6 @@ public class GagePP {
     private short p6HourSlot;
     
     public GagePP() {
-        // used_value_count = 0;
-        // ignored_value_count = 0;
-        // // total_value_count = 0;
-        // group_count = 0;
     }
 
     /**
@@ -135,7 +129,6 @@ public class GagePP {
         // double elapsed_time;
 
         int prev_dur = 0;
-        // String prev_key = null;
         int use_value;
         short precip_val;
         short hour = 1;
@@ -151,11 +144,8 @@ public class GagePP {
         int status = GPP_OK;
         
         logger.info("Processing records at " + btime);
-
         
-
-        Calendar dt = Calendar.getInstance(SHEFTimezone.GMT_TIMEZONE);
-        dt.setTime(rec.getObsTime());
+        Calendar dt = TimeTools.newCalendar(rec.getObsTime().getTime());
 
         HourlyppId id = new HourlyppId(rec.getLocationId(), rec.getTypeSource()
                 .getCode(), btime);
@@ -545,8 +535,8 @@ public class GagePP {
     private void gage_pp_1hour_slot(final GagePPOptions pOptions,
             final String pPE, PrecipRecord rec) {
         Calendar dt = Calendar.getInstance(SHEFTimezone.GMT_TIMEZONE);
-        Date datetime = rec.getObsTime();
-        dt.setTime(datetime);
+        dt.setTime(rec.getObsTime());
+
         int hour = dt.get(Calendar.HOUR_OF_DAY);
 
         int minute = dt.get(Calendar.MINUTE);
@@ -656,34 +646,30 @@ public class GagePP {
             final Calendar ansi_obstime_year_sec, String ansi_date_year_day,
             short [] p6HourSlot, char[] p6HourOffsetCode) {
 
-        float ppq_window;
+        float ppq_window = pOptions.getIntppq();
+        ppq_window *= SECONDS_PER_HOUR;
+        
         int bottom_6_hour_period;
         int diff1;
         int diff2;
-        int hour;
-        int minute;
+        int hour = ansi_obstime_year_sec.get(Calendar.HOUR_OF_DAY);
+        int minute = ansi_obstime_year_sec.get(Calendar.MINUTE);
         int num_periods;
         int remainder;
         int top_6_hour_period;
-        Calendar num_seconds_since_00z = Calendar
-                .getInstance(SHEFTimezone.GMT_TIMEZONE);
+//        Calendar num_seconds_since_00z = Calendar
+//                .getInstance(SHEFTimezone.GMT_TIMEZONE);
 
-        ppq_window = pOptions.getIntppq();
-        ppq_window *= SECONDS_PER_HOUR;
+        int num_seconds_since_00z = (hour * SECONDS_PER_HOUR)
+                + (minute * SECONDS_PER_MINUTE);
 
-
-        hour = ansi_obstime_year_sec.get(Calendar.HOUR_OF_DAY);
-        minute = ansi_obstime_year_sec.get(Calendar.MINUTE);
-
-        num_seconds_since_00z.setTimeInMillis((hour * SECONDS_PER_HOUR)
-                + (minute * SECONDS_PER_MINUTE));
-
-        bottom_6_hour_period = (int) (num_seconds_since_00z.getTimeInMillis() / SECONDS_IN_6HOUR_PERIOD);
+        bottom_6_hour_period = num_seconds_since_00z / SECONDS_IN_6HOUR_PERIOD;
         top_6_hour_period = bottom_6_hour_period + 1;
 
-        diff1 = (int) (num_seconds_since_00z.getTimeInMillis() - (bottom_6_hour_period * SECONDS_IN_6HOUR_PERIOD));
+        diff1 = num_seconds_since_00z
+                - (bottom_6_hour_period * SECONDS_IN_6HOUR_PERIOD);
         diff2 = (top_6_hour_period * SECONDS_IN_6HOUR_PERIOD)
-                - (int) num_seconds_since_00z.getTimeInMillis();
+                - num_seconds_since_00z;
 
         if (diff1 < diff2) {
             /*
diff --git a/edexOsgi/com.raytheon.edex.plugin.shef/src/com/raytheon/edex/plugin/shef/ohdlib/GagePPWrite.java b/edexOsgi/com.raytheon.edex.plugin.shef/src/com/raytheon/edex/plugin/shef/ohdlib/GagePPWrite.java
index 12adc135be..eb82755dba 100644
--- a/edexOsgi/com.raytheon.edex.plugin.shef/src/com/raytheon/edex/plugin/shef/ohdlib/GagePPWrite.java
+++ b/edexOsgi/com.raytheon.edex.plugin.shef/src/com/raytheon/edex/plugin/shef/ohdlib/GagePPWrite.java
@@ -28,6 +28,8 @@ import java.util.List;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
+import com.raytheon.edex.plugin.shef.ohdlib.GagePPOptions.upd_action;
+import com.raytheon.uf.common.dataplugin.persist.PersistableDataObject;
 import com.raytheon.uf.common.dataplugin.shef.tables.Dailypp;
 import com.raytheon.uf.common.dataplugin.shef.tables.DailyppId;
 import com.raytheon.uf.common.dataplugin.shef.tables.Hourlypc;
@@ -35,11 +37,8 @@ import com.raytheon.uf.common.dataplugin.shef.tables.HourlypcId;
 import com.raytheon.uf.common.dataplugin.shef.tables.Hourlypp;
 import com.raytheon.uf.common.dataplugin.shef.tables.HourlyppId;
 import com.raytheon.uf.common.dataplugin.shef.tables.IHourlyTS;
-import com.raytheon.edex.plugin.shef.ohdlib.GagePPOptions.upd_action;
-import com.raytheon.uf.common.dataplugin.persist.PersistableDataObject;
 import com.raytheon.uf.common.dataplugin.shef.util.SHEFTimezone;
 import com.raytheon.uf.common.dataplugin.shef.util.ShefConstants;
-import com.raytheon.uf.common.dataplugin.shef.util.ShefQC;
 import com.raytheon.uf.edex.database.dao.CoreDao;
 import com.raytheon.uf.edex.database.dao.DaoConfig;
 import com.raytheon.uf.edex.decodertools.time.TimeTools;
@@ -63,10 +62,6 @@ import com.raytheon.uf.edex.decodertools.time.TimeTools;
 public final class GagePPWrite {
     private static Log logger = LogFactory.getLog(GagePPWrite.class);
     
-    private static final float MISSING_PRECIP = -9999f;
-
-    private Date datetime;
-
     private char hourly_qc[] = new char[PrecipUtils.NUM_HOURLY_SLOTS];
 
     private char minute_offset[] = new char[PrecipUtils.NUM_HOURLY_SLOTS];
@@ -81,8 +76,6 @@ public final class GagePPWrite {
      * Empty constructor.
      */
     public GagePPWrite() {
-        
-        
         // sdf = new SimpleDateFormat(ShefConstants.POSTGRES_DATE_STRING);
         sdf = new SimpleDateFormat("yyyy-MM-dd");
         sdf.setTimeZone(SHEFTimezone.GMT_TIMEZONE);
@@ -106,9 +99,7 @@ public final class GagePPWrite {
             char manual_qc_code) {
 
 
-        datetime = dtime;
-        Calendar dt = TimeTools.getSystemCalendar();
-        dt.setTime(datetime);
+        Calendar dt = TimeTools.newCalendar(dtime.getTime());
 
         int hour_slot = dt.get(Calendar.HOUR_OF_DAY);
         Arrays.fill(hourly_qc, '-');
diff --git a/edexOsgi/com.raytheon.edex.plugin.shef/src/com/raytheon/edex/plugin/shef/ohdlib/PrecipUtils.java b/edexOsgi/com.raytheon.edex.plugin.shef/src/com/raytheon/edex/plugin/shef/ohdlib/PrecipUtils.java
index a551a85cd4..e1aae192b1 100644
--- a/edexOsgi/com.raytheon.edex.plugin.shef/src/com/raytheon/edex/plugin/shef/ohdlib/PrecipUtils.java
+++ b/edexOsgi/com.raytheon.edex.plugin.shef/src/com/raytheon/edex/plugin/shef/ohdlib/PrecipUtils.java
@@ -45,8 +45,6 @@ public abstract class PrecipUtils {
 
     private static final char ZERO_OFFSET = '0';
     
-    private static final AppsDefaults APPS_DEFAULTS = AppsDefaults.getInstance();
-
     public static final int NUM_HOURLY_SLOTS = 24;
 
     public static final int NUM_6HOURLY_SLOTS = 4;
@@ -71,6 +69,7 @@ public abstract class PrecipUtils {
      * @param options
      */
     public static void get_precip_window(GagePPOptions options) {
+        AppsDefaults APPS_DEFAULTS = AppsDefaults.getInstance();
         options.setIntpc(APPS_DEFAULTS.getInt("intpc",10));
         options.setIntlppp(APPS_DEFAULTS.getInt("intlppp",10));
         options.setIntuppp(APPS_DEFAULTS.getInt("intuppp",10));
@@ -109,7 +108,7 @@ public abstract class PrecipUtils {
      * @return
      */
     public static float get_6hour_precip_window() {
-        return APPS_DEFAULTS.getFloat("intppq", 2.0f);
+        return AppsDefaults.getInstance().getFloat("intppq", 2.0f);
     }
     
     /**
@@ -771,7 +770,7 @@ public abstract class PrecipUtils {
              */
 
             /* Get the search window around local 7 AM. */
-            int local_7am_window = APPS_DEFAULTS.getInt("ppp_ppd_local_7am_window", 3);
+            int local_7am_window = AppsDefaults.getInstance().getInt("ppp_ppd_local_7am_window", 3);
 
             Calendar c = new GregorianCalendar(SHEFTimezone.GMT_TIMEZONE);
             c.setTime(time12z);
diff --git a/edexOsgi/com.raytheon.edex.plugin.shef/src/com/raytheon/edex/transform/shef/AbstractShefTransformer.java b/edexOsgi/com.raytheon.edex.plugin.shef/src/com/raytheon/edex/transform/shef/AbstractShefTransformer.java
index 3be5f7c97b..2ecc01e3da 100644
--- a/edexOsgi/com.raytheon.edex.plugin.shef/src/com/raytheon/edex/transform/shef/AbstractShefTransformer.java
+++ b/edexOsgi/com.raytheon.edex.plugin.shef/src/com/raytheon/edex/transform/shef/AbstractShefTransformer.java
@@ -35,6 +35,7 @@ import com.raytheon.uf.common.dataplugin.PluginDataObject;
 import com.raytheon.uf.common.ohd.AppsDefaults;
 import com.raytheon.uf.edex.decodertools.core.DecoderTools;
 import com.raytheon.uf.edex.decodertools.time.TimeTools;
+import com.raytheon.uf.edex.wmo.message.WMOHeader;
 
 /**
  * Base class for observation data to SHEF conversions.
@@ -142,7 +143,6 @@ public abstract class AbstractShefTransformer
      * @param objects
      * @return
      */
-    @SuppressWarnings("unchecked")
     public static Iterator iterate(PluginDataObject[] objects) {
         Iterator it = null;
         if (objects != null) {
@@ -203,11 +203,15 @@ public abstract class AbstractShefTransformer
      * @return
      */
     protected StringBuilder makeWMOHeader(StringBuilder buffer,
-            String stationId, Headers headers) {
-
-        Calendar c = TimeTools.getSystemCalendar((String) headers
-                .get(DecoderTools.INGEST_FILE_NAME));
+            String stationId, Headers headers, WMOHeader hdr) {
 
+        Calendar c = null;
+        
+        if((hdr != null)&&(headers != null)) {
+            c = TimeTools.findDataTime(hdr.getYYGGgg(), headers);
+        } else {
+            c = TimeTools.getSystemCalendar();
+        }
         buffer.append(String.format(WMO_HEADER_FMT, stationId, c));
         
         return buffer;
diff --git a/edexOsgi/com.raytheon.edex.plugin.shef/src/com/raytheon/edex/transform/shef/MetarToShefTransformer.java b/edexOsgi/com.raytheon.edex.plugin.shef/src/com/raytheon/edex/transform/shef/MetarToShefTransformer.java
index c2f618a76f..c6dd3f1f3b 100644
--- a/edexOsgi/com.raytheon.edex.plugin.shef/src/com/raytheon/edex/transform/shef/MetarToShefTransformer.java
+++ b/edexOsgi/com.raytheon.edex.plugin.shef/src/com/raytheon/edex/transform/shef/MetarToShefTransformer.java
@@ -116,7 +116,7 @@ public class MetarToShefTransformer extends
                     String stnId = rec.getStationId();
                     place = 2;
                     StringBuilder sb = makeWMOHeader(openWMOMessage(0, 200),
-                            stnId, headers);
+                            stnId, headers, hdr);
                     place = 3;
 
                     startMessageLine(sb);
@@ -414,6 +414,14 @@ public class MetarToShefTransformer extends
         newobs = writeObs(newobs,sb.toString());
         
         System.out.println(newobs);
+     
+        Calendar c = TimeTools.getBaseCalendar(2011, 11, 30);
+        c.set(Calendar.HOUR_OF_DAY, 16);
+        c.set(Calendar.MINUTE, 21);
+        
+        
+        System.out.println(String.format(WMO_HEADER_FMT, "KOMA", c));
+       
         
     }
 }
diff --git a/edexOsgi/com.raytheon.edex.plugin.shef/src/com/raytheon/edex/transform/shef/SMToShefTransformer.java b/edexOsgi/com.raytheon.edex.plugin.shef/src/com/raytheon/edex/transform/shef/SMToShefTransformer.java
index b4ead4a65a..fa378d2189 100644
--- a/edexOsgi/com.raytheon.edex.plugin.shef/src/com/raytheon/edex/transform/shef/SMToShefTransformer.java
+++ b/edexOsgi/com.raytheon.edex.plugin.shef/src/com/raytheon/edex/transform/shef/SMToShefTransformer.java
@@ -30,6 +30,7 @@ import com.raytheon.uf.common.dataplugin.sfcobs.ObsCommon;
 import com.raytheon.uf.edex.decodertools.core.DecoderTools;
 import com.raytheon.uf.edex.decodertools.core.IDecoderConstants;
 import com.raytheon.uf.edex.decodertools.time.TimeTools;
+import com.raytheon.uf.edex.wmo.message.WMOHeader;
 
 /**
  * Transforms a decoded synoptic observation into a series of SHEF encoded data
@@ -84,8 +85,10 @@ public class SMToShefTransformer extends AbstractShefTransformer {
                 // Currently returns false, so nothing is encoded at this time.
                 if (encodeThisStation(rec)) {
 
+                    WMOHeader hdr = new WMOHeader(rec.getObsText().getBytes());
+
                     StringBuilder sb = makeWMOHeader(openWMOMessage(0, 200),
-                            "KWOH", headers);
+                            "KWOH", headers, hdr);
 
                     startMessageLine(sb)
                             .append(":SHEF derived data created by SMToShefTransformer");
diff --git a/edexOsgi/com.raytheon.uf.edex.decodertools/src/com/raytheon/uf/edex/decodertools/bufr/BUFRSection1.java b/edexOsgi/com.raytheon.uf.edex.decodertools/src/com/raytheon/uf/edex/decodertools/bufr/BUFRSection1.java
index 8004597d51..7c0295e32d 100644
--- a/edexOsgi/com.raytheon.uf.edex.decodertools/src/com/raytheon/uf/edex/decodertools/bufr/BUFRSection1.java
+++ b/edexOsgi/com.raytheon.uf.edex.decodertools/src/com/raytheon/uf/edex/decodertools/bufr/BUFRSection1.java
@@ -128,11 +128,7 @@ public abstract class BUFRSection1 extends BUFRSection {
      * @return
      */
     public Calendar getSectionDate() {
-        Calendar cal = TimeTools.getSystemCalendar();
-
-        cal.set(Calendar.YEAR, year);
-        cal.set(Calendar.MONTH, month - 1);
-        cal.set(Calendar.DAY_OF_MONTH, day);
+        Calendar cal = TimeTools.getBaseCalendar(year, month, day);
         cal.set(Calendar.HOUR_OF_DAY, hour);
         cal.set(Calendar.MINUTE, minute);
 
diff --git a/edexOsgi/com.raytheon.uf.edex.decodertools/src/com/raytheon/uf/edex/decodertools/time/TimeTools.java b/edexOsgi/com.raytheon.uf.edex.decodertools/src/com/raytheon/uf/edex/decodertools/time/TimeTools.java
index 736a2532a2..e709657fd8 100644
--- a/edexOsgi/com.raytheon.uf.edex.decodertools/src/com/raytheon/uf/edex/decodertools/time/TimeTools.java
+++ b/edexOsgi/com.raytheon.uf.edex.decodertools/src/com/raytheon/uf/edex/decodertools/time/TimeTools.java
@@ -20,6 +20,7 @@
 package com.raytheon.uf.edex.decodertools.time;
 
 import java.text.ParseException;
+import java.text.SimpleDateFormat;
 import java.util.Calendar;
 import java.util.TimeZone;
 import java.util.regex.Matcher;
@@ -55,33 +56,63 @@ import com.raytheon.uf.edex.decodertools.core.DecoderTools;
  */
 public class TimeTools {
 
+    /**
+     * Time stamp that includes the receipt time
+     * format : YYYYMMDD
+     */
+    public static final Pattern FILE_TIMESTAMP = Pattern.compile("(.*\\.)(\\d{8}$)");
+    
+    public static final Pattern WMO_TIMESTAMP = Pattern.compile("([0-3][0-9])(\\d{2})(\\d{2})[Zz]?");
+
+    public static final int HOURS_DAY = 24;
+    
+    public static final int MINUTES_HOUR = 60;
+    
     public static final int SECONDS_HOUR = 3600;
 
-    public static final int SECONDS_DAY = 24 * SECONDS_HOUR;
+    public static final int SECONDS_DAY = HOURS_DAY * SECONDS_HOUR;
 
     public static final long MILLIS_HOUR = 1000L * SECONDS_HOUR;
 
-    public static final long MILLIS_DAY = MILLIS_HOUR * 24L;
+    public static final long MILLIS_DAY = MILLIS_HOUR * HOURS_DAY;
 
     public static final String ZULU_TIMEZONE = "Zulu";
 
     private static ITimeService timeService = null;
 
     private static final Log logger = LogFactory.getLog(TimeTools.class);
-
+    
+    /**
+     * 
+     * @return
+     */
+    public static boolean allowArchive() {
+        return ("true".equalsIgnoreCase(System.getenv().get("ALLOW_ARCHIVE_DATA")));
+    }
+ 
     /**
      * Get a calendar that expresses the current system time. If an ITimeService
      * provider is registered, the time is retrieved from the service.
      * 
      * @return The current time as a GMT Calendar.
      */
-    public static Calendar getSystemCalendar() {
+    public static final Calendar getSystemCalendar() {
         Calendar retCal = null;
         if (timeService != null) {
             retCal = timeService.getCalendar();
         } else {
             retCal = Calendar.getInstance(TimeZone.getTimeZone(ZULU_TIMEZONE));
         }
+        if(retCal != null) {
+            TimeZone tz = retCal.getTimeZone();
+            if(tz != null) {
+                if (0 != tz.getRawOffset()) {
+                    retCal.setTimeZone(TimeZone.getTimeZone(ZULU_TIMEZONE));
+                }
+            } else {
+                retCal.setTimeZone(TimeZone.getTimeZone(ZULU_TIMEZONE));
+            }
+        }
         return retCal;
     }
 
@@ -91,46 +122,74 @@ public class TimeTools {
      * 
      * @return The current time as a GMT Calendar.
      */
-    public static Calendar getSystemCalendar(int year, int month, int day) {
+    public static final Calendar getSystemCalendar(int year, int month, int day) {
+        return getSystemCalendar(year, month, day, 0, 0);
+    }
+
+    /**
+     * Get a calendar that expresses the current system time based from specified
+     * date information if the 
+     * @param year Year to set.
+     * @param month
+     * @param day
+     * @param hour
+     * @param minute
+     * @return The current time as a GMT Calendar.
+     */
+    public static final Calendar getSystemCalendar(int year, int month,
+            int day, int hour, int minute) {
         Calendar retCal = getSystemCalendar();
-        String allow = System.getenv("ALLOW_ARCHIVE_DATA");
-        if ("true".equalsIgnoreCase(allow)) {
-            if (year != -1) {
-                retCal.set(Calendar.YEAR, year);
-            }
-            if (month != -1) {
-                retCal.set(Calendar.MONTH, month - 1);
-            }
-            if (day != -1) {
-                retCal.set(Calendar.DATE, day);
+        if (allowArchive()) {
+            if (isValidDate(year, month, day)) {
+                if (hour != -1) {
+                    if (minute != -1) {
+                        retCal.set(Calendar.YEAR, year);
+                        retCal.set(Calendar.MONTH, month - 1);
+                        retCal.set(Calendar.DAY_OF_MONTH, day);
+                        retCal.set(Calendar.HOUR_OF_DAY, hour);
+                        retCal.set(Calendar.MINUTE, minute);
+                        retCal.set(Calendar.SECOND, 0);
+                        retCal.set(Calendar.MILLISECOND, 0);
+                    }
+                }
             }
         }
         return retCal;
     }
 
-    public static Calendar getSystemCalendar(String fileName) {
+    /**
+     * 
+     * @param fileName
+     * @return
+     */
+    public static final Calendar getSystemCalendar(String fileName) {
         int year = -1;
         int month = -1;
         int day = -1;
-        if (fileName != null && fileName.matches(".*\\.\\d{8}$")) {
-            Pattern pattern = Pattern.compile("(.*\\.)(\\d{8}$)");
-            Matcher matcher = pattern.matcher(fileName);
-            matcher.find();
-            String yyyymmdd = matcher.group(2);
-            year = Integer.parseInt(yyyymmdd.substring(0, 4));
-            month = Integer.parseInt(yyyymmdd.substring(4, 6));
-            day = Integer.parseInt(yyyymmdd.substring(6, 8));
-
+        if(fileName != null) {
+            Matcher matcher = FILE_TIMESTAMP.matcher(fileName);
+            if(matcher.find()) {
+                String yyyymmdd = matcher.group(2);
+                try {
+                    year = Integer.parseInt(yyyymmdd.substring(0, 4));
+                    month = Integer.parseInt(yyyymmdd.substring(4, 6));
+                    day = Integer.parseInt(yyyymmdd.substring(6, 8));
+                } catch (NumberFormatException nfe) {
+                    year = -1;
+                    month = -1;
+                    day = -1;
+                }
+            }
         }
-        return getSystemCalendar(year, month, day);
+        return getSystemCalendar(year, month, day, 0, 0);
     }
-
+    
     /**
      * Converts a ddhhmm time group to a Calendar. Adjusts the calendar as
      * follows: Any time group with a day (dd) in the future is set back one
      * month.
      * 
-     * @param baseTime
+     * @param wmoDateStamp
      *            the time to convert
      * 
      * @return the converted time
@@ -138,25 +197,52 @@ public class TimeTools {
      * @throws DataFormatException
      *             if an error occurs
      */
-    public static Calendar findCurrentTime(String baseTime, String fileName)
+    public static final Calendar findCurrentTime(String wmoDateStamp, String fileName)
             throws DataFormatException {
-        Calendar retVal = getSystemCalendar(fileName);
+        Calendar refCal = getSystemCalendar(fileName);
         try {
-            String regexe = "(\\d{2})(\\d{2})(\\d{2})[Zz]?";
-            Pattern pattern = Pattern.compile(regexe);
-            Matcher matcher = pattern.matcher(baseTime);
+            Matcher matcher = WMO_TIMESTAMP.matcher(wmoDateStamp);
             if (matcher.matches()) {
-                adjustDayHourMinute(retVal, matcher.group(1), matcher.group(2),
-                        matcher.group(3));
+                int iDay = Integer.parseInt(matcher.group(1));
+                int iHour = Integer.parseInt(matcher.group(2));
+                int iMinute = Integer.parseInt(matcher.group(3));
+                
+                refCal = adjustDayHourMinute(refCal, iDay, iHour, iMinute);
             } else {
-                throw new ParseException("Invalid format - does not match "
-                        + regexe, 0);
+                throw new ParseException("Invalid format - time does not match "
+                        + WMO_TIMESTAMP.pattern(), 0);
             }
         } catch (Exception e) {
             throw new DataFormatException("Unable to find current time for "
-                    + baseTime + ", exception was " + e.toString());
+                    + wmoDateStamp + ", exception was " + e.toString());
         }
-        return retVal;
+        return refCal;
+    }
+
+    /**
+     * Convert a string in ddhhmm format to a standard {@link Calendar} format
+     * where ddhhmm is the GMT format while the standard time is in Calendar
+     * format with Year and Month information. Usage: ddhhmm is the issue time
+     * whereas utcTime can be the MDN time. The former comes "after" the latter.
+     * 
+     * @parm ddhhmm day-hour-minute in GMT
+     * @parm local Time UTC time in Calendar
+     */
+    public static final Calendar findDataTime(String ddhhmm, Headers headers) {
+        Calendar issueTime = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
+        String fileName = null;
+        if (headers != null) {
+            fileName = (String) headers.get(DecoderTools.INGEST_FILE_NAME);
+        }
+        try {
+            issueTime = findCurrentTime(ddhhmm, fileName);
+        } catch (DataFormatException e) {
+            if (logger.isInfoEnabled()) {
+                logger.info(" Error in processing MND time; return current time ");
+            }
+            issueTime = null;
+        }
+        return issueTime;
     }
 
     /**
@@ -174,31 +260,78 @@ public class TimeTools {
      * @param minute
      *            the new minute of the hour
      */
-    private static void adjustDayHourMinute(Calendar cal, String day,
-            String hour, String minute) {
-        int iDay = Integer.parseInt(day);
-        int iHour = Integer.parseInt(hour);
-        int iMinute = Integer.parseInt(minute);
-        int iMonth = cal.get(Calendar.MONTH);
-        int iYear = cal.get(Calendar.YEAR);
-        // adjust the month and year for roll-over situations
-        if (iDay > cal.get(Calendar.DAY_OF_MONTH)) {
-            iMonth--;
-            if (iMonth < 0) {
-                iMonth = Calendar.DECEMBER;
-                iYear--;
+    private static Calendar adjustDayHourMinute(Calendar cal, int wmoDay,
+            int wmoHour, int wmoMinute) {
+        if (cal != null) {
+
+            int cDay = cal.get(Calendar.DAY_OF_MONTH);
+
+            cal.set(Calendar.SECOND, 0);
+            cal.set(Calendar.MILLISECOND, 0);
+
+            // Range check hour/minute first. Have to wait for
+            // checking the day
+            if (isValidHour(wmoHour) && (isValidMinSec(wmoMinute))) {
+                Calendar lastMonth = copy(cal);
+                lastMonth.set(Calendar.DAY_OF_MONTH, 1);
+                lastMonth.add(Calendar.MONTH, -1);
+
+                // Get the maximum day of the current month from the reference
+                // calendar
+                int maxDayThisMonth = cal
+                        .getActualMaximum(Calendar.DAY_OF_MONTH);
+                // Set the day to one so all add/subtracts work correctly
+                cal.set(Calendar.DAY_OF_MONTH, 1);
+                cal.set(Calendar.HOUR_OF_DAY, wmoHour);
+                cal.set(Calendar.MINUTE, wmoMinute);
+                if (wmoDay == 1) {
+                    // the wmoDay is 1
+                    // and the reference calendar is the last
+                    // day of the month
+                    if (cDay == maxDayThisMonth) {
+                        // This is potentially next month's data received early
+                        // Allow three hours into the next day
+                        if (wmoHour < 3) {
+                            // Advance to the next month
+                            cal.add(Calendar.MONTH, 1);
+                            // and set the hour, minute
+                        }
+                    }
+                } else if (wmoDay > cDay) {
+                    // Is the wmoDay valid for this month?
+                    if(wmoDay <= maxDayThisMonth) {
+                        // First allow up to 3 hours into the next day
+                        if ((cDay + 1) == wmoDay) {
+                            // This is potentially next month's data received early
+                            // Allow three hours into the next day
+                            if (wmoHour > 2) {
+                                // Back up a month
+                                cal.add(Calendar.MONTH, -1);
+                            }
+                        } else {
+                            // Back up a month
+                            cal.add(Calendar.MONTH, -1);
+                            int mDay = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
+                            if(mDay < wmoDay) {
+                                cal.add(Calendar.MONTH, -1);
+                            }
+                        }
+                    } else {
+                        // The wmoDay is greater than the maximum number
+                        // of days for the reference month. We can't back
+                        // up one month, but can always back up two months.
+                        cal.add(Calendar.MONTH, -2);
+                    }
+                }
+                cal.set(Calendar.DAY_OF_MONTH, wmoDay);
+            } else {
+                // bad 
+                cal = null;
             }
         }
-        cal.set(Calendar.SECOND, 0);
-        cal.set(Calendar.MILLISECOND, 0);
-        cal.set(Calendar.YEAR, iYear);
-        cal.set(Calendar.MONTH, iMonth);
-        cal.set(Calendar.DAY_OF_MONTH, iDay);
-        cal.set(Calendar.HOUR_OF_DAY, iHour);
-        cal.set(Calendar.MINUTE, iMinute);
-
-    }
-
+        return cal;
+    }    
+    
     /**
      * Set the time service. To clear an existing service, set a null reference.
      * 
@@ -207,7 +340,7 @@ public class TimeTools {
      *            service.
      * @return The TimeService that had been previously defined.
      */
-    public static ITimeService setTimeService(ITimeService service) {
+    public static final ITimeService setTimeService(ITimeService service) {
         ITimeService retService = null;
         // get the current service if any.
         retService = timeService;
@@ -227,7 +360,7 @@ public class TimeTools {
      *            Day of the month [1..31] varies by month rules.
      * @return
      */
-    public static Calendar getBaseCalendar(int year, int month, int day) {
+    public static final Calendar getBaseCalendar(int year, int month, int day) {
         Calendar calendar = null;
 
         calendar = getSystemCalendar();
@@ -243,7 +376,7 @@ public class TimeTools {
 
         return calendar;
     }
-
+    
     /**
      * Get a new GMT time-zone calendar set to a specified time in milliseconds.
      * 
@@ -251,7 +384,7 @@ public class TimeTools {
      *            The time to set in milliseconds.
      * @return The new calendar instance.
      */
-    public static Calendar newCalendar(long timeInMillis) {
+    public static final Calendar newCalendar(long timeInMillis) {
         Calendar calendar = getSystemCalendar();
 
         calendar.setTimeInMillis(timeInMillis);
@@ -266,22 +399,23 @@ public class TimeTools {
      *            The calendar to copy.
      * @return The copied calendar.
      */
-    public static Calendar copy(Calendar calendar) {
+    public static final Calendar copy(Calendar calendar) {
         Calendar retValue = null;
         if (calendar != null) {
-            retValue = (Calendar) calendar.clone();
+            retValue = newCalendar(calendar.getTimeInMillis());
+            retValue.setTimeZone(calendar.getTimeZone());
         }
         return retValue;
     }
 
     /**
-     * Make a copy of a calendar instance to the nearest hour.
+     * Make a copy of a calendar instance truncated to the hour.
      * 
      * @param calendar
      *            The calendar to copy.
      * @return The copied calendar.
      */
-    public static Calendar copyToNearestHour(Calendar calendar) {
+    public static final Calendar copyToNearestHour(Calendar calendar) {
         Calendar retValue = null;
         if (calendar != null) {
             retValue = (Calendar) calendar.clone();
@@ -299,7 +433,7 @@ public class TimeTools {
      *            The calendar to copy.
      * @return The copied calendar.
      */
-    public static Calendar roundToNearestHour(Calendar calendar) {
+    public static final Calendar roundToNearestHour(Calendar calendar) {
         Calendar retValue = null;
         if (calendar != null) {
             retValue = (Calendar) calendar.clone();
@@ -322,7 +456,7 @@ public class TimeTools {
      *            Number of days to add or subtract.
      * @return The modified calendar.
      */
-    public static Calendar rollByDays(Calendar calendar, int byDays) {
+    public static final Calendar rollByDays(Calendar calendar, int byDays) {
         if (calendar != null) {
             long millis = calendar.getTimeInMillis();
 
@@ -342,7 +476,7 @@ public class TimeTools {
      *            Number of hours to add or subtract.
      * @return The modified calendar.
      */
-    public static Calendar rollByHours(Calendar calendar, int byHours) {
+    public static final Calendar rollByHours(Calendar calendar, int byHours) {
         if (calendar != null) {
             long millis = calendar.getTimeInMillis();
 
@@ -354,28 +488,196 @@ public class TimeTools {
     }
 
     /**
-     * Convert a string in ddhhmm format to a standard {@link Calendar} format
-     * where ddhhmm is the GMT format while the standard time is in Calendar
-     * format with Year and Month information. Usage: ddhhmm is the issue time
-     * whereas utcTime can be the MDN time. The former comes "after" the latter.
-     * 
-     * @parm ddhhmm day-hour-minute in GMT
-     * @parm local Time UTC time in Calendar
+     * Is the year valid. This method supposes any positive year
+     * value as valid.
+     * @param year The year to check.
+     * @return Is the year valid?
      */
-    public static Calendar findDataTime(String ddhhmm, Headers headers) {
-        Calendar issueTime = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
-        String fileName = null;
-        if (headers != null) {
-            fileName = (String) headers.get(DecoderTools.INGEST_FILE_NAME);
-        }
-        try {
-            return issueTime = findCurrentTime(ddhhmm, fileName);
-        } catch (DataFormatException e) {
-            if (logger.isInfoEnabled()) {
-                logger.info(" Error in processing MND time; return current time ");
-            }
-            return issueTime;
-        }
+    public static final boolean isValidYear(int year) {
+        return (year >= 0);
+    }
+    
+    /**
+     * The the specified month of the year valid.
+     * @param month Numeric value of the month.
+     * @return Is the month valid?
+     */
+    public static final boolean isValidMonth(int month) {
+        return ((month > -1)&&(month <= 12));
     }
 
+    /**
+     * Is the specified hour of the day valid? Range 0..23 inclusive. 
+     * @param hour The hour to check.
+     * @return Is the hour valid?
+     */
+    public static final boolean isValidHour(int hour) {
+        return ((hour > -1)&&(hour < HOURS_DAY));
+    }
+    
+    /**
+     * Is the specified minute/second valid? Range 0..59 inclusive. 
+     * @param hour The minute/second to check.
+     * @return Is the minute/second valid?
+     */
+    public static final boolean isValidMinSec(int value) {
+        return ((value > -1)&&(value < MINUTES_HOUR));
+    }
+    
+    
+    /**
+     * Is a specified date valid? This method checks an entire
+     * year, month, day timestamp.
+     * @param year The year to check.
+     * @param month Numeric value of the month.
+     * @param day Is the month valid?
+     * @return Is year, month, day timestamp valid.
+     */
+    public static final boolean isValidDate(int year, int month, int day) {
+        boolean validDay = false;
+        if(day > -1) {
+            if(isValidYear(year)) {
+                if(isValidMonth(month)) {
+                    Calendar c = getBaseCalendar(year, month, 1);
+                    int lastDay = c.getActualMaximum(Calendar.DAY_OF_MONTH) + 1;
+                    
+                    validDay = (day < lastDay);
+                }
+            }
+        }
+        return validDay;
+    }
+   
+    /**
+     * End of month, end of year
+     *
+     * @return test passed status
+     */
+    private static boolean test(String [] data) {
+        String expected = data[3];
+        System.out.print(String.format("Test Step %12s  ", data[0]));
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        Headers header = new Headers();
+        header.put(DecoderTools.INGEST_FILE_NAME, data[1]);
+        
+        Calendar c = findDataTime(data[2],header);
+        sdf.setTimeZone(c.getTimeZone());
+        
+        String cs = sdf.format(c.getTime());
+        System.out.print(String.format("%20s  expected %20s ",cs, expected));
+        return expected.equals(cs);
+    }
+    
+    public static final void main(String [] args) {
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        sdf.setTimeZone(TimeZone.getTimeZone(ZULU_TIMEZONE));
+
+        ITimeService service = new ITimeService() {
+            @Override
+            public Calendar getCalendar() {
+                final Calendar c = Calendar.getInstance();
+                c.setTimeZone(TimeZone.getTimeZone(ZULU_TIMEZONE));
+                c.set(Calendar.YEAR, 2011);
+                c.set(Calendar.MONTH, Calendar.JULY);
+                c.set(Calendar.DAY_OF_MONTH,15);
+                c.set(Calendar.HOUR_OF_DAY, 14);
+                c.set(Calendar.MINUTE, 15);
+                c.set(Calendar.SECOND, 32);
+                c.set(Calendar.MILLISECOND, 268);
+
+                return c;
+            }
+        };
+        TimeTools.setTimeService(service);
+
+        if(allowArchive()) {
+            String [] [] archiveData = {
+                    { "test001","UANT01_CWAO_171653_225472224.20110717", "171653","2011-07-17 16:53:00", },
+                    { "test002","UANT01_CWAO_312315_225472224.20110731", "312315","2011-07-31 23:15:00", },
+                    { "test003","UANT01_CWAO_312315_225472224.20110801", "312315","2011-07-31 23:15:00", },
+                    { "test004","UANT01_CWAO_170000_225472224.20110716", "170000","2011-07-17 00:00:00", },
+                    { "test005","UANT01_CWAO_170000_225472224.20110717", "170000","2011-07-17 00:00:00", },
+                    { "test006","UANT01_CWAO_100000_225472224.20111109", "100000","2011-11-10 00:00:00", },
+                    { "test007","UANT01_CWAO_010000_225472224.20111231", "010000","2012-01-01 00:00:00", },
+                    { "test008","UANT01_CWAO_312350_225472224.20120101", "312350","2011-12-31 23:50:00", },
+                    { "test009","UANT01_CWAO_010259_225472224.20111231", "010259","2012-01-01 02:59:00", },
+                    { "test010","UANT01_CWAO_010300_225472224.20111231", "010300","2011-12-01 03:00:00", },
+                    { "test011","UANT01_CWAO_290050_225472224.20120228", "290050","2012-02-29 00:50:00", },
+                    { "test012","UANT01_CWAO_010100_225472224.20120229", "010100","2012-03-01 01:00:00", },
+            };
+            System.out.println("Performing archive mode data tests");
+            for(String [] d : archiveData) {
+                System.out.println("  status = " + (test(d) ? "passed" : "failed"));
+            }
+        }
+        if(!allowArchive()) {
+            System.out.println("Performing non-archive mode data tests");
+            
+            System.out.println(String.format("Base time = %s", sdf.format(getSystemCalendar().getTime())));
+            // 2011-07-15 14:15:32.268
+            String[][] data = {
+                    { "test001", "UANT01_CWAO_171653_225472224.20110717", "171653",
+                            "2011-06-17 16:53:00", },
+                    { "test002", "UANT01_CWAO_312315_225472224.20110731", "312315",
+                            "2011-05-31 23:15:00", },
+            };
+            for (String[] d : data) {
+                System.out.println("  status = " + (test(d) ? "passed" : "failed"));
+            }
+            //**********************************************************************
+            service = new ITimeService() {
+                @Override
+                public Calendar getCalendar() {
+                    final Calendar c = Calendar.getInstance();
+                    c.setTimeZone(TimeZone.getTimeZone(ZULU_TIMEZONE));
+                    c.set(Calendar.YEAR, 2011);
+                    c.set(Calendar.MONTH, Calendar.AUGUST);
+                    c.set(Calendar.DAY_OF_MONTH,1);
+                    c.set(Calendar.HOUR_OF_DAY, 14);
+                    c.set(Calendar.MINUTE, 15);
+                    c.set(Calendar.SECOND, 32);
+                    c.set(Calendar.MILLISECOND, 268);
+
+                    return c;
+                }
+            };
+            TimeTools.setTimeService(service);
+            System.out.println(String.format("Base time = %s", sdf.format(getSystemCalendar().getTime())));
+            
+            data = new String [][] {
+                    { "test011", "UANT01_CWAO_312353_225472224.20110717", "312353",
+                            "2011-07-31 23:53:00", },
+            };
+            for (String[] d : data) {
+                System.out.println("  status = " + (test(d) ? "passed" : "failed"));
+            }
+            //**********************************************************************
+            service = new ITimeService() {
+                @Override
+                public Calendar getCalendar() {
+                    final Calendar c = Calendar.getInstance();
+                    c.setTimeZone(TimeZone.getTimeZone(ZULU_TIMEZONE));
+                    c.set(Calendar.YEAR, 2011);
+                    c.set(Calendar.MONTH, Calendar.JULY);
+                    c.set(Calendar.DAY_OF_MONTH,31);
+                    c.set(Calendar.HOUR_OF_DAY, 22);
+                    c.set(Calendar.MINUTE, 45);
+                    c.set(Calendar.SECOND, 32);
+                    c.set(Calendar.MILLISECOND, 268);
+
+                    return c;
+                }
+            };
+            TimeTools.setTimeService(service);
+            System.out.println(String.format("Base time = %s", sdf.format(getSystemCalendar().getTime())));
+
+            data = new String [][] {
+                    { "test011", "UANT01_CWAO_010053_225472224.20110717", "010053",
+                            "2011-08-01 00:53:00", },
+            };
+            for (String[] d : data) {
+                System.out.println("  status = " + (test(d) ? "passed" : "failed"));
+            }
+        }
+    }
 }
diff --git a/edexOsgi/com.raytheon.uf.edex.decodertools/src/com/raytheon/uf/edex/wmo/message/WMOHeader.java b/edexOsgi/com.raytheon.uf.edex.decodertools/src/com/raytheon/uf/edex/wmo/message/WMOHeader.java
index 9205463b50..6045c09665 100644
--- a/edexOsgi/com.raytheon.uf.edex.decodertools/src/com/raytheon/uf/edex/wmo/message/WMOHeader.java
+++ b/edexOsgi/com.raytheon.uf.edex.decodertools/src/com/raytheon/uf/edex/wmo/message/WMOHeader.java
@@ -169,10 +169,16 @@ public class WMOHeader {
                 }
                 YYGGgg = wmoHeader.substring(hdrIndex, hdrIndex + DTGROUP_SIZE);
                 parseDateTime(YYGGgg);
-                Calendar obsTime = TimeTools.findDataTime(YYGGgg, headers);
-                headerYear = obsTime.get(Calendar.YEAR);
-                headerMonth = obsTime.get(Calendar.MONTH) + 1;
-
+                headerDate = TimeTools.findDataTime(YYGGgg, headers);
+                // At this point headerDate will either be the current time (non-archive) or
+                // a time generated from the WMOHeader and filename dateStamp
+                
+                headerYear = headerDate.get(Calendar.YEAR);
+                headerMonth = headerDate.get(Calendar.MONTH) + 1;
+                headerDay = headerDate.get(Calendar.DAY_OF_MONTH);
+                headerHour = headerDate.get(Calendar.HOUR_OF_DAY);
+                headerMinute = headerDate.get(Calendar.MINUTE);
+                
                 hdrIndex += DTGROUP_SIZE;
 
                 // Everything else goes here for now. Leave it to the client to
@@ -346,10 +352,6 @@ public class WMOHeader {
      * @return the headerDate
      */
     public Calendar getHeaderDate() {
-        // Use lazy construction here.
-        if (headerDate == null) {
-            headerDate = createCalendarDate();
-        }
         return headerDate;
     }
 
@@ -402,53 +404,53 @@ public class WMOHeader {
         }
     }
 
-    /**
-     * Use the parsed date/time elements to create the Calendar date time info
-     * for this WMO header. The logic in this method allows the WMO header time
-     * to be set to the current day, the next day, or up to 25 days in the past.
-     * 
-     * @return A Calendar instance based on the current system date time.
-     */
-    private Calendar createCalendarDate() {
-        Calendar msgDate = null;
-        // check the internal data first
-        if ((headerDay > -1) && (headerHour > -1) && (headerMinute > -1)) {
-            Calendar currentClock = TimeTools.getSystemCalendar(headerYear,
-                    headerMonth, -1);
-
-            Calendar obsDate = null;
-            Calendar tTime = TimeTools.copyToNearestHour(currentClock);
-            // Set to the next day.
-            TimeTools.rollByDays(tTime, 1);
-
-            if (headerDay == currentClock.get(Calendar.DAY_OF_MONTH)) {
-                obsDate = TimeTools.copyToNearestHour(currentClock);
-                obsDate.set(Calendar.HOUR_OF_DAY, headerHour);
-                obsDate.set(Calendar.MINUTE, headerMinute);
-            } else if (headerDay == tTime.get(Calendar.DAY_OF_MONTH)) {
-                // Observation time is in the next day
-                obsDate = TimeTools.copyToNearestHour(tTime);
-                obsDate.set(Calendar.HOUR_OF_DAY, headerHour);
-                obsDate.set(Calendar.MINUTE, headerMinute);
-            } else {
-                tTime = TimeTools.copyToNearestHour(currentClock);
-                int i = 0;
-                while (i++ < 25) {
-                    // Go back a day
-                    TimeTools.rollByDays(tTime, -1);
-                    if (headerDay == tTime.get(Calendar.DAY_OF_MONTH)) {
-                        // Day values are equal, so this is it.
-                        obsDate = TimeTools.copyToNearestHour(tTime);
-                        obsDate.set(Calendar.HOUR_OF_DAY, headerHour);
-                        obsDate.set(Calendar.MINUTE, headerMinute);
-                        break;
-                    }
-                }
-            }
-            if (obsDate != null) {
-                msgDate = obsDate;
-            }
-        }
-        return msgDate;
-    }
+//    /**
+//     * Use the parsed date/time elements to create the Calendar date time info
+//     * for this WMO header. The logic in this method allows the WMO header time
+//     * to be set to the current day, the next day, or up to 25 days in the past.
+//     * 
+//     * @return A Calendar instance based on the current system date time.
+//     */
+//    private Calendar createCalendarDate() {
+//        Calendar msgDate = null;
+//        // check the internal data first
+//        if ((headerDay > -1) && (headerHour > -1) && (headerMinute > -1)) {
+//            Calendar currentClock = TimeTools.getSystemCalendar(headerYear,
+//                    headerMonth, headerDay);
+//
+//            Calendar obsDate = null;
+//            Calendar tTime = TimeTools.copyToNearestHour(currentClock);
+//            // Set to the next day.
+//            TimeTools.rollByDays(tTime, 1);
+//
+//            if (headerDay == currentClock.get(Calendar.DAY_OF_MONTH)) {
+//                obsDate = TimeTools.copyToNearestHour(currentClock);
+//                obsDate.set(Calendar.HOUR_OF_DAY, headerHour);
+//                obsDate.set(Calendar.MINUTE, headerMinute);
+//            } else if (headerDay == tTime.get(Calendar.DAY_OF_MONTH)) {
+//                // Observation time is in the next day
+//                obsDate = TimeTools.copyToNearestHour(tTime);
+//                obsDate.set(Calendar.HOUR_OF_DAY, headerHour);
+//                obsDate.set(Calendar.MINUTE, headerMinute);
+//            } else {
+//                tTime = TimeTools.copyToNearestHour(currentClock);
+//                int i = 0;
+//                while (i++ < 25) {
+//                    // Go back a day
+//                    TimeTools.rollByDays(tTime, -1);
+//                    if (headerDay == tTime.get(Calendar.DAY_OF_MONTH)) {
+//                        // Day values are equal, so this is it.
+//                        obsDate = TimeTools.copyToNearestHour(tTime);
+//                        obsDate.set(Calendar.HOUR_OF_DAY, headerHour);
+//                        obsDate.set(Calendar.MINUTE, headerMinute);
+//                        break;
+//                    }
+//                }
+//            }
+//            if (obsDate != null) {
+//                msgDate = obsDate;
+//            }
+//        }
+//        return msgDate;
+//    }
 }
diff --git a/edexOsgi/com.raytheon.uf.edex.plugin.acarssounding/src/com/raytheon/uf/edex/plugin/acarssounding/ACARSSounding.java b/edexOsgi/com.raytheon.uf.edex.plugin.acarssounding/src/com/raytheon/uf/edex/plugin/acarssounding/ACARSSounding.java
index ed5c6e7aaf..ae81e1039a 100644
--- a/edexOsgi/com.raytheon.uf.edex.plugin.acarssounding/src/com/raytheon/uf/edex/plugin/acarssounding/ACARSSounding.java
+++ b/edexOsgi/com.raytheon.uf.edex.plugin.acarssounding/src/com/raytheon/uf/edex/plugin/acarssounding/ACARSSounding.java
@@ -236,9 +236,9 @@ public class ACARSSounding {
         String msg = "attempting " + acftInfo.getTailNumber() + " ";
         String tailNumber = acftInfo.getTailNumber();
 
-        Calendar c = TimeTools.getSystemCalendar();
-        c.setTimeInMillis(acftInfo.getStartTime());
+        Calendar c = TimeTools.newCalendar(acftInfo.getStartTime());
         msg += String.format(ACARSSoundingTools.STD_TM_FMT,c);
+
         c.setTimeInMillis(acftInfo.getStopTime());
         msg += "->";
         msg += String.format(ACARSSoundingTools.STD_TM_FMT,c);