Source code for analysis.decimal_time

from datetime import datetime, timedelta
import numpy as np

[docs] def decimal_time_precise(year, month, day, hour=0, minute=0, second=0, start=0): """ Convert year-month-day-hour-minute-second to decimal time format, handling various cases including negative seconds Parameters: year: Year (can be scalar or array) month: Month (can be scalar or array) day: Day (can be scalar or array) hour, minute, second: Hour, minute, second (can be scalar or array) start: Starting year (default is 0) Returns: Decimal time format (relative to starting year) """ # Convert to numpy arrays for uniform processing year = np.atleast_1d(np.array(year, dtype=float)) month = np.atleast_1d(np.array(month, dtype=float)) day = np.atleast_1d(np.array(day, dtype=float)) hour = np.atleast_1d(np.array(hour, dtype=float)) minute = np.atleast_1d(np.array(minute, dtype=float)) second = np.atleast_1d(np.array(second, dtype=float)) # Check if input is scalar scalar_input = (len(year) == 1) # Correct month = 0 cases month[month == 0] = 1 # Adjust array lengths n = len(year) if len(month) < n: month = np.resize(month, n) if len(day) < n: day = np.resize(day, n) if len(hour) < n: hour = np.resize(hour, n) if len(minute) < n: minute = np.resize(minute, n) if len(second) < n: second = np.resize(second, n) results = [] for i in range(n): # Handle negative seconds # Normalize time to valid hour-minute-second total_seconds = int(hour[i]) * 3600 + int(minute[i]) * 60 + second[i] # Handle negative total seconds (subtract a day and adjust) days_adjust = 0 while total_seconds < 0: total_seconds += 86400 # Add one day in seconds days_adjust -= 1 # Decrease one day # Recalculate hour, minute and second hr_int = int(total_seconds // 3600) % 24 min_int = int((total_seconds % 3600) // 60) sec_int = int(total_seconds % 60) sec_frac = total_seconds - int(total_seconds) # Calculate datetime try: # Ensure date and month are valid day_val = max(1, int(day[i])) month_val = max(1, int(month[i])) # Create base datetime base_dt = datetime(int(year[i]), month_val, day_val) # Add day adjustment (handle date decrease due to negative seconds) if days_adjust != 0: base_dt += timedelta(days=days_adjust) # Add time component dt = datetime( base_dt.year, base_dt.month, base_dt.day, hr_int, min_int, sec_int ) # Add fractional seconds if sec_frac > 0: dt += timedelta(seconds=sec_frac) except ValueError as e: print(f"Warning: Invalid date calculation for {int(year[i])}-{month_val}-{day_val}, Error: {e}") # Use the first day of the month as alternative, ensuring time component is valid try: dt = datetime(int(year[i]), month_val, 1, hr_int, min_int, sec_int) print(f"Using first day of month instead: {dt}") except ValueError: # If still fails, use the most basic valid date and time print(f"Fallback to basic valid date") dt = datetime(int(year[i]), 1, 1, 0, 0, 0) # Calculate the first day of the year year_start = datetime(int(year[i]), 1, 1) # Calculate days in the year (handle leap year) if int(year[i]) % 4 == 0 and (int(year[i]) % 100 != 0 or int(year[i]) % 400 == 0): days_in_year = 366 else: days_in_year = 365 # Calculate days passed from year start to now (including hour-minute-second) days_passed = (dt - year_start).total_seconds() / 86400 # Calculate decimal time decimal_time = (year[i] - start) + days_passed / days_in_year results.append(decimal_time) # Return result (scalar or array) if scalar_input: return results[0] return np.array(results)
[docs] def ymd_time_precise(time, start): """ Convert decimal time to year-month-day format, using datetime library Parameters: time: Decimal time (can be scalar or array) start: Starting year Returns: Array containing year, month, day (each row corresponds to one time point) """ # Convert to numpy array for uniform processing time = np.atleast_1d(np.array(time, dtype=float)) # Check if input is scalar scalar_input = (len(time) == 1) # Create result array containing year, month, day result = np.zeros((len(time), 3)) for i in range(len(time)): try: # Calculate full year full_year = int(time[i]) + int(start) # Calculate fractional part of year year_fraction = time[i] - int(time[i]) # Determine days in the year (handle leap year) if full_year % 4 == 0 and (full_year % 100 != 0 or full_year % 400 == 0): days_in_year = 366 else: days_in_year = 365 # Calculate days passed (including fractional part) days_passed = year_fraction * days_in_year # Separate integer days and fractional part days_int = int(days_passed) days_frac = days_passed - days_int # Calculate corresponding date target_date = datetime(full_year, 1, 1) + timedelta(days=days_int) # Store year-month-day result result[i, 0] = full_year result[i, 1] = target_date.month result[i, 2] = target_date.day except Exception as e: print(f"Warning: Error converting time {time[i]} + {start}: {e}") # Use default value (January 1st of current year) result[i, 0] = int(start) result[i, 1] = 1 result[i, 2] = 1 # Return result (scalar or array) if scalar_input: return result[0] return result