CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-cdflib

A Python CDF reader toolkit for reading and writing CDF files without requiring NASA CDF library installation

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

epochs.mddocs/

Time Epoch Conversion

Comprehensive time handling system supporting all three CDF epoch formats with conversion between CDF epochs, Unix timestamps, numpy datetime64, and human-readable strings. The CDFepoch class provides static methods for working with time data in scientific applications.

CDF Epoch Formats

CDF supports three time formats, each optimized for different precision and range requirements:

  1. CDF_EPOCH: Milliseconds since Year 0 (8-byte float)
  2. CDF_EPOCH16: Picoseconds since Year 0 (16-byte complex)
  3. CDF_TIME_TT2000: Nanoseconds since J2000 with leap seconds (8-byte integer)

Capabilities

Generic Time Operations

Automatic format detection and conversion operations that work with any CDF epoch type.

class CDFepoch:
    @staticmethod
    def encode(epochs, iso_8601=True):
        """
        Encode CDF epochs to human-readable strings.
        
        Parameters:
        - epochs (int | float | complex | array-like): CDF epoch values of any type
        - iso_8601 (bool): Use ISO 8601 format if True, CDF format if False
        
        Returns:
        str | list[str]: Encoded time string(s)
        """
    
    @staticmethod
    def breakdown(epochs):
        """
        Break down CDF epochs into date/time components.
        
        Parameters:
        - epochs (int | float | complex | array-like): CDF epoch values of any type
        
        Returns:
        numpy.ndarray: Array with shape (..., 9) containing:
                      [year, month, day, hour, minute, second, millisecond, 
                       microsecond, nanosecond] for each epoch
        """
    
    @staticmethod
    def to_datetime(cdf_time):
        """
        Convert CDF time to numpy datetime64 array.
        
        Parameters:
        - cdf_time (int | float | complex | array-like): CDF epoch values
        
        Returns:
        numpy.ndarray[datetime64]: NumPy datetime64 array
        """
    
    @staticmethod
    def unixtime(cdf_time):
        """
        Convert CDF time to Unix timestamp (seconds since 1970-01-01).
        
        Parameters:
        - cdf_time (int | float | complex | array-like): CDF epoch values
        
        Returns:
        float | numpy.ndarray: Unix timestamp(s)
        """
    
    @staticmethod
    def compute(datetimes):
        """
        Auto-detect appropriate CDF epoch type and compute from date components.
        
        Parameters:
        - datetimes (array-like): Date/time components as nested lists/arrays
                                 [[year, month, day, hour, min, sec, ms], ...]
        
        Returns:
        int | float | complex | numpy.ndarray: Appropriate CDF epoch type
        """

Usage Examples:

import cdflib

# Auto-detect and encode different epoch types
epoch_float = 63731251200000.0  # CDF_EPOCH
epoch_tt2000 = 725846462184000000  # TT2000
epoch_16 = complex(63731251200, 0)  # CDF_EPOCH16

# Encode to human-readable strings
print(cdflib.cdfepoch.encode(epoch_float))     # "01-Jan-2021 00:00:00.000"
print(cdflib.cdfepoch.encode(epoch_tt2000))    # "01-Jan-2023 00:01:02.184000000"
print(cdflib.cdfepoch.encode(epoch_16))        # "01-Jan-2021 00:00:00.000000000000"

# Break down to components
components = cdflib.cdfepoch.breakdown([epoch_float, epoch_tt2000])
print(components)  # [[2021, 1, 1, 0, 0, 0, 0, 0, 0], [2023, 1, 1, 0, 1, 2, 184, 0, 0]]

# Convert to numpy datetime64
dt_array = cdflib.cdfepoch.to_datetime([epoch_float, epoch_tt2000])
print(dt_array)    # ['2021-01-01T00:00:00.000' '2023-01-01T00:01:02.184']

# Convert to Unix timestamp
unix_times = cdflib.cdfepoch.unixtime([epoch_float, epoch_tt2000])
print(unix_times)  # [1609459200.0, 1672531262.184]

Unix Time Conversion

Convert Unix timestamps to different CDF epoch formats.

@staticmethod
def timestamp_to_cdfepoch(unixtime_data):
    """
    Convert Unix timestamp to CDF_EPOCH format.
    
    Parameters:
    - unixtime_data (float | array-like): Unix timestamp(s) in seconds
    
    Returns:
    numpy.ndarray: CDF_EPOCH values (milliseconds since Year 0)
    """

@staticmethod  
def timestamp_to_cdfepoch16(unixtime_data):
    """
    Convert Unix timestamp to CDF_EPOCH16 format.
    
    Parameters:
    - unixtime_data (float | array-like): Unix timestamp(s) in seconds
    
    Returns:
    numpy.ndarray: CDF_EPOCH16 values (picoseconds since Year 0)
    """

@staticmethod
def timestamp_to_tt2000(unixtime_data):
    """
    Convert Unix timestamp to TT2000 format.
    
    Parameters:
    - unixtime_data (float | array-like): Unix timestamp(s) in seconds
    
    Returns:
    numpy.ndarray: TT2000 values (nanoseconds since J2000)
    """

Usage Examples:

import cdflib
import time

# Current Unix timestamp
current_time = time.time()  # e.g., 1672531262.184

# Convert to different CDF epoch formats
cdf_epoch = cdflib.cdfepoch.timestamp_to_cdfepoch(current_time)
cdf_epoch16 = cdflib.cdfepoch.timestamp_to_cdfepoch16(current_time)
tt2000 = cdflib.cdfepoch.timestamp_to_tt2000(current_time)

print(f"CDF_EPOCH: {cdf_epoch[0]}")      # Milliseconds since Year 0
print(f"CDF_EPOCH16: {cdf_epoch16[0]}")  # Complex number (picoseconds)
print(f"TT2000: {tt2000[0]}")            # Nanoseconds since J2000

# Convert array of timestamps
timestamps = [1672531200.0, 1672531262.184, 1672531300.0]
epochs = cdflib.cdfepoch.timestamp_to_cdfepoch(timestamps)
print(f"Converted epochs: {epochs}")

CDF_EPOCH Operations

Operations specific to CDF_EPOCH format (milliseconds since Year 0).

@staticmethod
def encode_epoch(epochs, iso_8601=True):
    """
    Encode CDF_EPOCH values to strings.
    
    Parameters:
    - epochs (float | array-like): CDF_EPOCH values
    - iso_8601 (bool): Use ISO 8601 format if True
    
    Returns:
    str | list[str]: Encoded time string(s)
    """

@staticmethod
def compute_epoch(dates):
    """
    Compute CDF_EPOCH from date/time components.
    
    Parameters:
    - dates (array-like): Date components as [year, month, day, hour, min, sec, ms]
                         or nested array for multiple dates
    
    Returns:
    float | numpy.ndarray: CDF_EPOCH value(s)
    """

@staticmethod
def breakdown_epoch(epochs):
    """
    Break down CDF_EPOCH to date/time components.
    
    Parameters:
    - epochs (float | array-like): CDF_EPOCH values
    
    Returns:
    numpy.ndarray: Components [year, month, day, hour, min, sec, ms]
    """

@staticmethod
def epochrange_epoch(start_time, end_time, epochs):
    """
    Find CDF_EPOCH values within a time range.
    
    Parameters:
    - start_time (float): Start CDF_EPOCH value
    - end_time (float): End CDF_EPOCH value  
    - epochs (array-like): CDF_EPOCH array to search
    
    Returns:
    tuple: (indices, values) of epochs within range
    """

Usage Examples:

import cdflib

# Compute CDF_EPOCH from date components
date_components = [2023, 6, 15, 14, 30, 45, 123]
epoch = cdflib.cdfepoch.compute_epoch(date_components)
print(f"CDF_EPOCH: {epoch}")  # Single epoch value

# Multiple dates
dates = [
    [2023, 1, 1, 0, 0, 0, 0],
    [2023, 6, 15, 12, 0, 0, 0],
    [2023, 12, 31, 23, 59, 59, 999]
]
epochs = cdflib.cdfepoch.compute_epoch(dates)
print(f"Multiple epochs: {epochs}")

# Encode to strings
time_strings = cdflib.cdfepoch.encode_epoch(epochs)
print(f"Time strings: {time_strings}")

# ISO 8601 format
iso_strings = cdflib.cdfepoch.encode_epoch(epochs, iso_8601=True)
print(f"ISO format: {iso_strings}")

# Break down to components
components = cdflib.cdfepoch.breakdown_epoch(epochs)
print(f"Components shape: {components.shape}")  # (3, 7) for 3 epochs

# Find epochs within range
start_epoch = cdflib.cdfepoch.compute_epoch([2023, 3, 1, 0, 0, 0, 0])
end_epoch = cdflib.cdfepoch.compute_epoch([2023, 9, 1, 0, 0, 0, 0])
indices, values = cdflib.cdfepoch.epochrange_epoch(start_epoch, end_epoch, epochs)
print(f"Epochs in range: {values}")

CDF_EPOCH16 Operations

Operations for CDF_EPOCH16 format (picoseconds since Year 0, highest precision).

@staticmethod
def encode_epoch16(epochs, iso_8601=True):
    """
    Encode CDF_EPOCH16 values to strings.
    
    Parameters:
    - epochs (complex | array-like): CDF_EPOCH16 values
    - iso_8601 (bool): Use ISO 8601 format if True
    
    Returns:
    str | list[str]: Encoded time string(s) with picosecond precision
    """

@staticmethod
def compute_epoch16(datetimes):
    """
    Compute CDF_EPOCH16 from date/time components.
    
    Parameters:
    - datetimes (array-like): Components [year, month, day, hour, min, sec, ms, us, ns, ps]
                             or nested array for multiple dates
    
    Returns:
    complex | numpy.ndarray: CDF_EPOCH16 value(s)
    """

@staticmethod
def breakdown_epoch16(epochs):
    """
    Break down CDF_EPOCH16 to date/time components.
    
    Parameters:
    - epochs (complex | array-like): CDF_EPOCH16 values
    
    Returns:
    numpy.ndarray: Components [year, month, day, hour, min, sec, ms, us, ns, ps]
    """

@staticmethod
def epochrange_epoch16(start_time, end_time, epochs):
    """
    Find CDF_EPOCH16 values within a time range.
    
    Parameters:
    - start_time (complex): Start CDF_EPOCH16 value
    - end_time (complex): End CDF_EPOCH16 value
    - epochs (array-like): CDF_EPOCH16 array to search
    
    Returns:
    tuple: (indices, values) of epochs within range
    """

TT2000 Operations

Operations for TT2000 format (nanoseconds since J2000 with leap seconds).

@staticmethod
def encode_tt2000(tt2000, iso_8601=True):
    """
    Encode TT2000 values to strings.
    
    Parameters:
    - tt2000 (int | array-like): TT2000 values
    - iso_8601 (bool): Use ISO 8601 format if True
    
    Returns:
    str | list[str]: Encoded time string(s) with nanosecond precision
    """

@staticmethod
def compute_tt2000(datetimes):
    """
    Compute TT2000 from date/time components.
    
    Parameters:
    - datetimes (array-like): Components [year, month, day, hour, min, sec, ms, us, ns]
                             or nested array for multiple dates
    
    Returns:
    int | numpy.ndarray: TT2000 value(s)
    """

@staticmethod
def breakdown_tt2000(tt2000):
    """
    Break down TT2000 to date/time components.
    
    Parameters:
    - tt2000 (int | array-like): TT2000 values
    
    Returns:
    numpy.ndarray: Components [year, month, day, hour, min, sec, ms, us, ns]
    """

@staticmethod
def epochrange_tt2000(start_time, end_time, tt2000):
    """
    Find TT2000 values within a time range.
    
    Parameters:
    - start_time (int): Start TT2000 value
    - end_time (int): End TT2000 value
    - tt2000 (array-like): TT2000 array to search
    
    Returns:
    tuple: (indices, values) of TT2000 values within range
    """

Usage Examples:

import cdflib

# TT2000 with nanosecond precision
date_with_ns = [2023, 6, 15, 14, 30, 45, 123, 456, 789]
tt2000_value = cdflib.cdfepoch.compute_tt2000(date_with_ns)
print(f"TT2000: {tt2000_value}")

# Encode with nanosecond precision
tt2000_string = cdflib.cdfepoch.encode_tt2000(tt2000_value)
print(f"TT2000 string: {tt2000_string}")

# CDF_EPOCH16 with picosecond precision  
date_with_ps = [2023, 6, 15, 14, 30, 45, 123, 456, 789, 123]
epoch16_value = cdflib.cdfepoch.compute_epoch16(date_with_ps)
print(f"CDF_EPOCH16: {epoch16_value}")

# Break down TT2000
tt2000_components = cdflib.cdfepoch.breakdown_tt2000(tt2000_value)
print(f"TT2000 components: {tt2000_components}")  # Includes nanosecond component

Time Range Operations

Find epochs within specified time ranges for data filtering.

@staticmethod
def findepochrange(start_time, end_time, epochs):
    """
    Generic function to find epoch range regardless of format.
    
    Parameters:
    - start_time: Start time in same format as epochs
    - end_time: End time in same format as epochs  
    - epochs (array-like): Epoch array to search
    
    Returns:
    tuple: (start_index, end_index) of range boundaries
    """

Usage Example:

import cdflib

# Create sample epoch array
dates = [[2023, i, 1, 0, 0, 0, 0] for i in range(1, 13)]  # Monthly data
epochs = cdflib.cdfepoch.compute_epoch(dates)

# Find summer months (June to August) 
start_summer = cdflib.cdfepoch.compute_epoch([2023, 6, 1, 0, 0, 0, 0])
end_summer = cdflib.cdfepoch.compute_epoch([2023, 8, 31, 23, 59, 59, 999])

start_idx, end_idx = cdflib.cdfepoch.findepochrange(start_summer, end_summer, epochs)
summer_epochs = epochs[start_idx:end_idx+1]
summer_strings = cdflib.cdfepoch.encode_epoch(summer_epochs)
print(f"Summer months: {summer_strings}")

String Parsing

Parse time strings back to date components.

@staticmethod
def parse(value):
    """
    Parse time strings into date/time components.
    
    Parameters:
    - value (str | tuple[str] | list[str]): Time string(s) to parse
    
    Returns:
    numpy.ndarray: Date/time components array
    """

Usage Example:

import cdflib

# Parse various time string formats
time_strings = [
    "2023-06-15T14:30:45.123",
    "15-Jun-2023 14:30:45.123",
    "2023-12-31T23:59:59.999"
]

parsed_dates = cdflib.cdfepoch.parse(time_strings)
print(f"Parsed components: {parsed_dates}")

# Convert parsed dates to epochs
epochs = cdflib.cdfepoch.compute_epoch(parsed_dates)
print(f"Computed epochs: {epochs}")

Practical Examples

Scientific Time Series Analysis

import cdflib
import numpy as np

# Create hourly measurements for one day
base_date = [2023, 6, 15, 0, 0, 0, 0]
hourly_dates = [[2023, 6, 15, hour, 0, 0, 0] for hour in range(24)]

# Convert to different epoch formats for comparison
cdf_epochs = cdflib.cdfepoch.compute_epoch(hourly_dates)
tt2000_epochs = cdflib.cdfepoch.compute_tt2000(hourly_dates)

# Create synthetic temperature data
temperatures = 20 + 10 * np.sin(np.linspace(0, 2*np.pi, 24)) + np.random.normal(0, 1, 24)

# Find daytime hours (6 AM to 6 PM)
morning = cdflib.cdfepoch.compute_epoch([2023, 6, 15, 6, 0, 0, 0])
evening = cdflib.cdfepoch.compute_epoch([2023, 6, 15, 18, 0, 0, 0])

start_idx, end_idx = cdflib.cdfepoch.findepochrange(morning, evening, cdf_epochs)
daytime_temps = temperatures[start_idx:end_idx+1]
daytime_epochs = cdf_epochs[start_idx:end_idx+1]

print(f"Daytime temperature range: {np.min(daytime_temps):.1f} to {np.max(daytime_temps):.1f}°C")
print(f"Daytime period: {cdflib.cdfepoch.encode_epoch(daytime_epochs[0])} to {cdflib.cdfepoch.encode_epoch(daytime_epochs[-1])}")

Time Format Interoperability

import cdflib
import datetime

# Convert between different time representations
python_datetime = datetime.datetime(2023, 6, 15, 14, 30, 45, 123456)

# Convert to Unix timestamp
unix_time = python_datetime.timestamp()

# Convert Unix time to CDF formats
cdf_epoch = cdflib.cdfepoch.timestamp_to_cdfepoch(unix_time)[0]
tt2000 = cdflib.cdfepoch.timestamp_to_tt2000(unix_time)[0]

# Convert back to verify
unix_from_cdf = cdflib.cdfepoch.unixtime(cdf_epoch)
unix_from_tt2000 = cdflib.cdfepoch.unixtime(tt2000)

print(f"Original Unix time: {unix_time}")
print(f"From CDF_EPOCH: {unix_from_cdf}")
print(f"From TT2000: {unix_from_tt2000}")
print(f"Differences (microseconds): CDF={abs(unix_time-unix_from_cdf)*1e6:.1f}, TT2000={abs(unix_time-unix_from_tt2000)*1e6:.1f}")

# Display in human-readable format
print(f"CDF_EPOCH string: {cdflib.cdfepoch.encode_epoch(cdf_epoch)}")
print(f"TT2000 string: {cdflib.cdfepoch.encode_tt2000(tt2000)}")

Types

# Type aliases used in the epochs module
epoch_scalar_types = Union[int, np.int64, float, np.float64, complex, np.complex128]
epoch_list_types = Union[List[int], List[np.int64], List[float], List[np.float64], 
                        List[complex], List[np.complex128]]
epoch_types = Union[epoch_scalar_types, epoch_list_types, numpy.ndarray]

cdf_epoch_type = Union[float, np.float64, List[float], numpy.ndarray]
cdf_epoch16_type = Union[complex, np.complex128, List[complex], numpy.ndarray]  
cdf_tt2000_type = Union[int, np.int64, List[int], numpy.ndarray]

encoded_type = Union[str, List[str]]

Install with Tessl CLI

npx tessl i tessl/pypi-cdflib

docs

cdf-reading.md

cdf-writing.md

epochs.md

index.md

xarray-integration.md

tile.json