mirror of
				https://github.com/ciphervance/supercell-wx.git
				synced 2025-10-31 06:40:05 +00:00 
			
		
		
		
	Adding robust date calculation to WMO header
This commit is contained in:
		
							parent
							
								
									c00016cb69
								
							
						
					
					
						commit
						7e9895e002
					
				
					 3 changed files with 178 additions and 72 deletions
				
			
		|  | @ -119,71 +119,11 @@ std::chrono::system_clock::time_point Segment::event_begin() const | |||
|       // If event begin is 000000T0000Z
 | ||||
|       if (eventBegin == std::chrono::system_clock::time_point {}) | ||||
|       { | ||||
|          using namespace std::chrono; | ||||
| 
 | ||||
|          // Determine event end from P-VTEC string
 | ||||
|          system_clock::time_point eventEnd = | ||||
|          std::chrono::system_clock::time_point eventEnd = | ||||
|             header_->vtecString_[0].pVtec_.event_end(); | ||||
| 
 | ||||
|          auto           endDays = floor<days>(eventEnd); | ||||
|          year_month_day endDate {endDays}; | ||||
| 
 | ||||
|          // Determine WMO date/time
 | ||||
|          std::string wmoDateTime = wmoHeader_->date_time(); | ||||
| 
 | ||||
|          bool          wmoDateTimeValid = false; | ||||
|          unsigned int  dayOfMonth       = 0; | ||||
|          unsigned long beginHour        = 0; | ||||
|          unsigned long beginMinute      = 0; | ||||
| 
 | ||||
|          try | ||||
|          { | ||||
|             // WMO date time is in the format DDHHMM
 | ||||
|             dayOfMonth = | ||||
|                static_cast<unsigned int>(std::stoul(wmoDateTime.substr(0, 2))); | ||||
|             beginHour        = std::stoul(wmoDateTime.substr(2, 2)); | ||||
|             beginMinute      = std::stoul(wmoDateTime.substr(4, 2)); | ||||
|             wmoDateTimeValid = true; | ||||
|          } | ||||
|          catch (const std::exception&) | ||||
|          { | ||||
|             logger_->warn("Malformed WMO date/time: {}", wmoDateTime); | ||||
|          } | ||||
| 
 | ||||
|          if (wmoDateTimeValid) | ||||
|          { | ||||
|             // Combine end date year and month with WMO date time
 | ||||
|             eventBegin = | ||||
|                sys_days {endDate.year() / endDate.month() / day {dayOfMonth}} + | ||||
|                hours {beginHour} + minutes {beginMinute}; | ||||
| 
 | ||||
|             // If the begin date is after the end date, assume the start time
 | ||||
|             // was the previous month (give a 1 day grace period for expiring
 | ||||
|             // events in the past)
 | ||||
|             if (eventBegin > eventEnd + 24h) | ||||
|             { | ||||
|                // If the current end month is January
 | ||||
|                if (endDate.month() == January) | ||||
|                { | ||||
|                   // The begin month must be December of last year
 | ||||
|                   eventBegin = | ||||
|                      sys_days { | ||||
|                         year {static_cast<int>((endDate.year() - 1y).count())} / | ||||
|                         December / day {dayOfMonth}} + | ||||
|                      hours {beginHour} + minutes {beginMinute}; | ||||
|                } | ||||
|                else | ||||
|                { | ||||
|                   // Back up one month
 | ||||
|                   eventBegin = | ||||
|                      sys_days {endDate.year() / | ||||
|                                month {static_cast<unsigned int>( | ||||
|                                   (endDate.month() - month {1}).count())} / | ||||
|                                day {dayOfMonth}} + | ||||
|                      hours {beginHour} + minutes {beginMinute}; | ||||
|                } | ||||
|             } | ||||
|          } | ||||
|          eventBegin = wmoHeader_->GetDateTime(eventEnd); | ||||
|       } | ||||
|    } | ||||
| 
 | ||||
|  |  | |||
|  | @ -42,17 +42,26 @@ public: | |||
|    WmoHeaderImpl(const WmoHeaderImpl&&)            = delete; | ||||
|    WmoHeaderImpl& operator=(const WmoHeaderImpl&&) = delete; | ||||
| 
 | ||||
|    void CalculateAbsoluteDateTime(); | ||||
|    bool ParseDateTime(unsigned int&  dayOfMonth, | ||||
|                       unsigned long& hour, | ||||
|                       unsigned long& minute); | ||||
| 
 | ||||
|    bool operator==(const WmoHeaderImpl& o) const; | ||||
| 
 | ||||
|    std::string sequenceNumber_; | ||||
|    std::string dataType_; | ||||
|    std::string geographicDesignator_; | ||||
|    std::string bulletinId_; | ||||
|    std::string icao_; | ||||
|    std::string dateTime_; | ||||
|    std::string bbbIndicator_; | ||||
|    std::string productCategory_; | ||||
|    std::string productDesignator_; | ||||
|    std::string sequenceNumber_ {}; | ||||
|    std::string dataType_ {}; | ||||
|    std::string geographicDesignator_ {}; | ||||
|    std::string bulletinId_ {}; | ||||
|    std::string icao_ {}; | ||||
|    std::string dateTime_ {}; | ||||
|    std::string bbbIndicator_ {}; | ||||
|    std::string productCategory_ {}; | ||||
|    std::string productDesignator_ {}; | ||||
| 
 | ||||
|    std::optional<std::chrono::year_month> dateHint_ {}; | ||||
|    std::optional<std::chrono::sys_time<std::chrono::minutes>> | ||||
|       absoluteDateTime_ {}; | ||||
| }; | ||||
| 
 | ||||
| WmoHeader::WmoHeader() : p(std::make_unique<WmoHeaderImpl>()) {} | ||||
|  | @ -124,6 +133,71 @@ std::string WmoHeader::product_designator() const | |||
|    return p->productDesignator_; | ||||
| } | ||||
| 
 | ||||
| std::chrono::sys_time<std::chrono::minutes> WmoHeader::GetDateTime( | ||||
|    std::optional<std::chrono::system_clock::time_point> endTimeHint) | ||||
| { | ||||
|    std::chrono::sys_time<std::chrono::minutes> wmoDateTime {}; | ||||
| 
 | ||||
|    if (p->absoluteDateTime_.has_value()) | ||||
|    { | ||||
|       wmoDateTime = p->absoluteDateTime_.value(); | ||||
|    } | ||||
|    else if (endTimeHint.has_value()) | ||||
|    { | ||||
|       bool          dateTimeValid = false; | ||||
|       unsigned int  dayOfMonth    = 0; | ||||
|       unsigned long hour          = 0; | ||||
|       unsigned long minute        = 0; | ||||
| 
 | ||||
|       dateTimeValid = p->ParseDateTime(dayOfMonth, hour, minute); | ||||
| 
 | ||||
|       if (dateTimeValid) | ||||
|       { | ||||
|          using namespace std::chrono; | ||||
| 
 | ||||
|          auto           endDays = floor<days>(endTimeHint.value()); | ||||
|          year_month_day endDate {endDays}; | ||||
| 
 | ||||
|          // Combine end date year and month with WMO date time
 | ||||
|          wmoDateTime = | ||||
|             sys_days {endDate.year() / endDate.month() / day {dayOfMonth}} + | ||||
|             hours {hour} + minutes {minute}; | ||||
| 
 | ||||
|          // If the begin date is after the end date, assume the start time
 | ||||
|          // was the previous month (give a 1 day grace period for expiring
 | ||||
|          // events in the past)
 | ||||
|          if (wmoDateTime > endTimeHint.value() + 24h) | ||||
|          { | ||||
|             // If the current end month is January
 | ||||
|             if (endDate.month() == January) | ||||
|             { | ||||
|                year_month x = year {2024} / December; | ||||
|                sys_days   y; | ||||
| 
 | ||||
|                // The begin month must be December of last year
 | ||||
|                wmoDateTime = | ||||
|                   sys_days { | ||||
|                      year {static_cast<int>((endDate.year() - 1y).count())} / | ||||
|                      December / day {dayOfMonth}} + | ||||
|                   hours {hour} + minutes {minute}; | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                // Back up one month
 | ||||
|                wmoDateTime = | ||||
|                   sys_days {endDate.year() / | ||||
|                             month {static_cast<unsigned int>( | ||||
|                                (endDate.month() - month {1}).count())} / | ||||
|                             day {dayOfMonth}} + | ||||
|                   hours {hour} + minutes {minute}; | ||||
|             } | ||||
|          } | ||||
|       } | ||||
|    } | ||||
| 
 | ||||
|    return wmoDateTime; | ||||
| } | ||||
| 
 | ||||
| bool WmoHeader::Parse(std::istream& is) | ||||
| { | ||||
|    bool headerValid = true; | ||||
|  | @ -224,6 +298,8 @@ bool WmoHeader::Parse(std::istream& is) | |||
|          p->icao_                 = wmoTokenList[1]; | ||||
|          p->dateTime_             = wmoTokenList[2]; | ||||
| 
 | ||||
|          p->CalculateAbsoluteDateTime(); | ||||
| 
 | ||||
|          if (wmoTokenList.size() == 4) | ||||
|          { | ||||
|             p->bbbIndicator_ = wmoTokenList[3]; | ||||
|  | @ -255,4 +331,60 @@ bool WmoHeader::Parse(std::istream& is) | |||
|    return headerValid; | ||||
| } | ||||
| 
 | ||||
| void WmoHeader::SetDateHint(std::chrono::year_month dateHint) | ||||
| { | ||||
|    p->dateHint_ = dateHint; | ||||
|    p->CalculateAbsoluteDateTime(); | ||||
| } | ||||
| 
 | ||||
| bool WmoHeaderImpl::ParseDateTime(unsigned int&  dayOfMonth, | ||||
|                                   unsigned long& hour, | ||||
|                                   unsigned long& minute) | ||||
| { | ||||
|    bool dateTimeValid = false; | ||||
| 
 | ||||
|    try | ||||
|    { | ||||
|       // WMO date time is in the format DDHHMM
 | ||||
|       dayOfMonth = | ||||
|          static_cast<unsigned int>(std::stoul(dateTime_.substr(0, 2))); | ||||
|       hour          = std::stoul(dateTime_.substr(2, 2)); | ||||
|       minute        = std::stoul(dateTime_.substr(4, 2)); | ||||
|       dateTimeValid = true; | ||||
|    } | ||||
|    catch (const std::exception&) | ||||
|    { | ||||
|       logger_->warn("Malformed WMO date/time: {}", dateTime_); | ||||
|    } | ||||
| 
 | ||||
|    return dateTimeValid; | ||||
| } | ||||
| 
 | ||||
| void WmoHeaderImpl::CalculateAbsoluteDateTime() | ||||
| { | ||||
|    bool dateTimeValid = false; | ||||
| 
 | ||||
|    if (dateHint_.has_value() && !dateTime_.empty()) | ||||
|    { | ||||
|       unsigned int  dayOfMonth = 0; | ||||
|       unsigned long hour       = 0; | ||||
|       unsigned long minute     = 0; | ||||
| 
 | ||||
|       dateTimeValid = ParseDateTime(dayOfMonth, hour, minute); | ||||
| 
 | ||||
|       if (dateTimeValid) | ||||
|       { | ||||
|          using namespace std::chrono; | ||||
|          absoluteDateTime_ = sys_days {dateHint_->year() / dateHint_->month() / | ||||
|                                        day {dayOfMonth}} + | ||||
|                              hours {hour} + minutes {minute}; | ||||
|       } | ||||
|    } | ||||
| 
 | ||||
|    if (!dateTimeValid) | ||||
|    { | ||||
|       absoluteDateTime_.reset(); | ||||
|    } | ||||
| } | ||||
| 
 | ||||
| } // namespace scwx::awips
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Dan Paulat
						Dan Paulat