The Epoch class is the fundamental time representation in Brahe. It encapsulates a specific instant in time, defined by both a time representation and a time scale. The Epoch class provides methods for converting between different time representations and time scales, as well as for performing arithmetic operations on time instances.
There are even more capabilities and features of the Epoch class beyond what is covered in this guide. For a complete reference of all available methods and properties, please refer to the Epoch API Reference.
The most common way to create an Epoch is from date and time components. You can specify just a date (which defaults to midnight), or provide the full date and time including fractional seconds.
importbraheasbhbh.initialize_eop()# Create epoch from date only (midnight)epc1=bh.Epoch(2024,1,1)print(f"Date only: {epc1}")# Create epoch from full datetime componentsepc2=bh.Epoch(2024,6,15,14,30,45.5,0.0)print(f"Full datetime: {epc2}")# Create epoch with different time systemepc3=bh.Epoch(2024,12,25,18,0,0.0,0.0,time_system=bh.TimeSystem.GPS)print(f"GPS time system: {epc3}")# In Python you can also use the direct datetime constantepc4=bh.Epoch(2024,12,25,18,0,0.0,0.0,time_system=bh.TAI)print(f"GPS time system: {epc4}")
usebraheasbh;fnmain(){bh::initialize_eop().unwrap();// Create epoch from date only (midnight)letepc1=bh::Epoch::from_date(2024,1,1,bh::TimeSystem::UTC);println!("Date only: {}",epc1);// Create epoch from full datetime componentsletepc2=bh::Epoch::from_datetime(2024,6,15,14,30,45.5,0.0,bh::TimeSystem::UTC);println!("Full datetime: {}",epc2);// Create epoch with different time systemletepc3=bh::Epoch::from_datetime(2024,12,25,18,0,0.0,0.0,bh::TimeSystem::GPS);println!("GPS time system: {}",epc3);}
Date only: 2024-01-01 00:00:00.000 UTC
Full datetime: 2024-06-15 14:30:45.500 UTC
GPS time system: 2024-12-25 18:00:00.000 GPS
GPS time system: 2024-12-25 18:00:00.000 TAI
Modified Julian Date (MJD) is a commonly used time representation in astronomy and astrodynamics. MJD is defined as JD - 2400000.5, which makes it more convenient for modern dates.
importbraheasbhbh.initialize_eop()# The string can be an ISO 8601 formatepc1=bh.Epoch.from_string("2025-01-02T04:56:54.123Z")print(f"ISO 8601: {epc1}")# It can be a simple space-separated format with a time systemepc2=bh.Epoch.from_string("2024-06-15 14:30:45.500 GPS")print(f"Simple format: {epc2}")# It can be a datetime without a time system (defaults to UTC)epc3=bh.Epoch.from_string("2023-12-31 23:59:59")print(f"Datetime without time system: {epc3}")# Or it can just be a dateepc4=bh.Epoch.from_string("2022-07-04")print(f"Date only: {epc4}")
usebraheasbh;fnmain(){bh::initialize_eop().unwrap();// The string can be an ISO 8601 formatletepc1=bh::Epoch::from_string("2025-01-02T04:56:54.123Z").unwrap();println!("ISO 8601: {}",epc1);// It can be a simple space-separated format with a time systemletepc2=bh::Epoch::from_string("2024-06-15 14:30:45.500 GPS").unwrap();println!("Simple format: {}",epc2);// It can be a datetime without a time system (defaults to UTC)letepc3=bh::Epoch::from_string("2023-12-31 23:59:59").unwrap();println!("Datetime without time system: {}",epc3);// Or it can just be a dateletepc4=bh::Epoch::from_string("2022-07-04").unwrap();println!("Date only: {}",epc4);}
ISO 8601: 2025-01-02 04:56:54.123 UTC
Simple format: 2024-06-15 14:30:45.500 GPS
Datetime without time system: 2023-12-31 23:59:59.000 UTC
Date only: 2022-07-04 00:00:00.000 UTC
ISO 8601: 2025-01-02 04:56:54.123 UTC
Simple format: 2024-06-15 14:30:45.500 GPS
Datetime without time system: 2023-12-31 23:59:59.000 UTC
Date only: 2022-07-04 00:00:00.000 UTC
Every Epoch carries a TimeSystem, set at construction. It records the time scale the epoch is expressed in. For what each scale means and when to use it, see Time Systems and Representations.
In Python the time system is optional and defaults to UTC when omitted; it can be given either as an enumeration member (bh.TimeSystem.GPS) or as the equivalent module-level constant (bh.GPS). Rust requires it explicitly at construction, using bh::TimeSystem::GPS.
An Epoch stores an absolute instant, and the time system only determines the scale it reports in. to_time_system returns a new Epoch at the same instant expressed in a different scale — it changes how the epoch prints, not when it is. The original is left untouched, and the two compare equal because they denote the same instant.
To read a single value out in another scale without creating a new Epoch, use the *_as_time_system family: to_datetime_as_time_system, to_string_as_time_system, jd_as_time_system, mjd_as_time_system, day_of_year_as_time_system, and seconds_past_j2000_as_time_system.
importbraheasbhbh.initialize_eop()# The time system is set at construction. It defaults to UTC.epc_utc=bh.Epoch(2024,6,15,12,0,0.0,0.0)print(f"Default: {epc_utc}")# Specify a time system with the TimeSystem enumeration...epc_gps=bh.Epoch(2024,6,15,12,0,0.0,0.0,time_system=bh.TimeSystem.GPS)print(f"GPS: {epc_gps}")# ...or with the equivalent module-level constant.epc_tai=bh.Epoch(2024,6,15,12,0,0.0,0.0,time_system=bh.TAI)print(f"TAI: {epc_tai}")# Read back the time system an Epoch was created in.print(f"Read back: {epc_gps.time_system}")# The same calendar values in different time systems are different instants.print(f"UTC and GPS equal? {epc_utc==epc_gps}")# to_time_system returns a new Epoch at the SAME instant, displayed in a new# time system. It changes how the epoch prints, not when it is.epc_as_gps=epc_utc.to_time_system(bh.TimeSystem.GPS)print(f"As GPS: {epc_as_gps}")print(f"Same instant? {epc_utc==epc_as_gps}")# The original is untouched.print(f"Original: {epc_utc}")# To read a single value out in another system without making a new Epoch,# use the *_as_time_system projections.print(f"epc_utc as TAI: {epc_utc.to_string_as_time_system(bh.TimeSystem.TAI)}")print(f"MJD as UTC: {epc_utc.mjd_as_time_system(bh.TimeSystem.UTC):.9f}")print(f"MJD as TT: {epc_utc.mjd_as_time_system(bh.TimeSystem.TT):.9f}")
usebraheasbh;fnmain(){bh::initialize_eop().unwrap();// The time system is always explicit in Rust.letepc_utc=bh::Epoch::from_datetime(2024,6,15,12,0,0.0,0.0,bh::TimeSystem::UTC);println!("Default: {}",epc_utc);letepc_gps=bh::Epoch::from_datetime(2024,6,15,12,0,0.0,0.0,bh::TimeSystem::GPS);println!("GPS: {}",epc_gps);letepc_tai=bh::Epoch::from_datetime(2024,6,15,12,0,0.0,0.0,bh::TimeSystem::TAI);println!("TAI: {}",epc_tai);// Read back the time system an Epoch was created in. This is a field.println!("Read back: {}",epc_gps.time_system);// The same calendar values in different time systems are different instants.println!("UTC and GPS equal? {}",epc_utc==epc_gps);// to_time_system returns a new Epoch at the SAME instant, displayed in a// new time system. It changes how the epoch prints, not when it is.letepc_as_gps=epc_utc.to_time_system(bh::TimeSystem::GPS);println!("As GPS: {}",epc_as_gps);println!("Same instant? {}",epc_utc==epc_as_gps);// The original is untouched.println!("Original: {}",epc_utc);// To read a single value out in another system without making a new Epoch,// use the *_as_time_system projections.println!("epc_utc as TAI: {}",epc_utc.to_string_as_time_system(bh::TimeSystem::TAI));println!("MJD as UTC: {:.9}",epc_utc.mjd_as_time_system(bh::TimeSystem::UTC));println!("MJD as TT: {:.9}",epc_utc.mjd_as_time_system(bh::TimeSystem::TT));}
Default: 2024-06-15 12:00:00.000 UTC
GPS: 2024-06-15 12:00:00.000 GPS
TAI: 2024-06-15 12:00:00.000 TAI
Read back: GPS
UTC and GPS equal? False
As GPS: 2024-06-15 12:00:18.000 GPS
Same instant? True
Original: 2024-06-15 12:00:00.000 UTC
epc_utc as TAI: 2024-06-15 12:00:37.000 TAI
MJD as UTC: 60476.500000000
MJD as TT: 60476.500800741
Default: 2024-06-15 12:00:00.000 UTC
GPS: 2024-06-15 12:00:00.000 GPS
TAI: 2024-06-15 12:00:00.000 TAI
Read back: GPS
UTC and GPS equal? false
As GPS: 2024-06-15 12:00:18.000 GPS
Same instant? true
Original: 2024-06-15 12:00:00.000 UTC
epc_utc as TAI: 2024-06-15 12:00:37.000 TAI
MJD as UTC: 60476.500000000
MJD as TT: 60476.500800741
importbraheasbhbh.initialize_eop()# Create an epochepc=bh.Epoch(2025,1,1,12,0,0.0,0.0)print(f"Original epoch: {epc}")# You can add time in seconds to an Epoch and get a new Epoch back# Add 1 hour (3600 seconds)epc_plus_hour=epc+3600.0print(f"Plus 1 hour: {epc_plus_hour}")# Add 1 day (86400 seconds)epc_plus_day=epc+86400.0print(f"Plus 1 day: {epc_plus_day}")# You can also do in-place addition# Add 1 second in-placeepc+=1.0print(f"In-place plus 1 second: {epc}")# Add 1 milisecond in-placeepc+=0.001print(f"In-place plus 1 millisecond: {epc}")
usebraheasbh;fnmain(){bh::initialize_eop().unwrap();// Create an epochletepc=bh::Epoch::from_datetime(2025,1,1,12,0,0.0,0.0,bh::TimeSystem::UTC);println!("Original epoch: {}",epc);// You can add time in seconds to an Epoch and get a new Epoch back// Add 1 hour (3600 seconds)letepc_plus_hour=epc+3600.0;println!("Plus 1 hour: {}",epc_plus_hour);// Add 1 day (86400 seconds)letepc_plus_day=epc+86400.0;println!("Plus 1 day: {}",epc_plus_day);// You can also do in-place addition// Add 1 second in-placeletmutepc=epc;epc+=1.0;println!("In-place plus 1 second: {}",epc);// Add 1 millisecond in-placeepc+=0.001;println!("In-place plus 1 millisecond: {}",epc);}
Original epoch: 2025-01-01 12:00:00.000 UTC
Plus 1 hour: 2025-01-01 13:00:00.000 UTC
Plus 1 day: 2025-01-02 12:00:00.000 UTC
In-place plus 1 second: 2025-01-01 12:00:01.000 UTC
In-place plus 1 millisecond: 2025-01-01 12:00:01.001 UTC
Original epoch: 2025-01-01 12:00:00.000 UTC
Plus 1 hour: 2025-01-01 13:00:00.000 UTC
Plus 1 day: 2025-01-02 12:00:00.000 UTC
In-place plus 1 second: 2025-01-01 12:00:01.000 UTC
In-place plus 1 millisecond: 2025-01-01 12:00:01.001 UTC
importbraheasbhbh.initialize_eop()# You can subtract two Epoch instances to get the time difference in secondsepc1=bh.Epoch(2024,1,1,12,0,0.0,0.0)epc2=bh.Epoch(2024,1,2,12,1,1.0,0.0)dt=epc2-epc1print(f"Time difference: {dt:.1f} seconds")# You can also subtract a float (in seconds) from an Epoch to get a new Epochepc=bh.Epoch(2024,6,15,10,30,0.0,0.0)# Subtract 1 hour (3600 seconds)epc_minus_hour=epc-3600.0print(f"Minus 1 hour: {epc_minus_hour}")# You can also update an Epoch in-place by subtracting secondsepc=bh.Epoch(2024,1,1,0,0,0.0,0.0)epc-=61.0# Subtract 61 secondsprint(f"In-place minus 61 seconds: {epc}")
usebraheasbh;fnmain(){bh::initialize_eop().unwrap();// Create two epochsletepc1=bh::Epoch::from_datetime(2024,1,1,12,0,0.0,0.0,bh::TimeSystem::UTC);letepc2=bh::Epoch::from_datetime(2024,1,2,13,1,1.0,0.0,bh::TimeSystem::UTC);// Compute time difference in secondsletdt=epc2-epc1;println!("Time difference: {:.1} seconds",dt);// You can also subtract a float (in seconds) from an Epoch to get a new Epochletepc=bh::Epoch::from_datetime(2024,6,15,10,30,0.0,0.0,bh::TimeSystem::UTC);letepc_minus_hour=epc-3600.0;println!("Minus 1 hour: {}",epc_minus_hour);// You can also update an Epoch in-place by subtracting secondsletmutepc=bh::Epoch::from_datetime(2024,1,1,0,0,0.0,0.0,bh::TimeSystem::UTC);epc-=61.0;// Subtract 61 secondsprintln!("In-place minus 61 seconds: {}",epc);}
The Epoch class also supports comparison operations (e.g., equality, less than, greater than) to compare different time instances. It also supports methods for getting string representations using language-specific formatting options.
importbraheasbhbh.initialize_eop()# Create an epochepc_1=bh.Epoch(2024,1,1,12,0,0.0,0.0)epc_2=bh.Epoch(2024,1,1,12,0,0.0,1.0)epc_3=bh.Epoch(2024,1,1,12,0,0.0,0.0)# You can compare two Epoch instances for equalityprint(f"epc_1 == epc_2: {epc_1==epc_2}")print(f"epc_1 == epc_3: {epc_1==epc_3}")# You can also use inequality and comparison operatorsprint(f"epc_1 != epc_2: {epc_1!=epc_2}")print(f"epc_1 < epc_2: {epc_1<epc_2}")print(f"epc_2 < epc_1: {epc_2<epc_1}")print(f"epc_2 > epc_1: {epc_2>epc_1}")print(f"epc_1 <= epc_3: {epc_1<=epc_3}")print(f"epc_2 >= epc_1: {epc_2>=epc_1}")
usebraheasbh;fnmain(){bh::initialize_eop().unwrap();// Create an epochletepc_1=bh::Epoch::from_datetime(2024,1,1,12,0,0.0,0.0,bh::TimeSystem::UTC);letepc_2=bh::Epoch::from_datetime(2024,1,1,12,0,0.0,1.0,bh::TimeSystem::UTC);letepc_3=bh::Epoch::from_datetime(2024,1,1,12,0,0.0,0.0,bh::TimeSystem::UTC);// You can compare two Epoch instances for equalityprintln!("epc_1 == epc_2: {}",epc_1==epc_2);println!("epc_1 == epc_3: {}",epc_1==epc_3);// You can also use inequality and comparison operatorsprintln!("epc_1 != epc_2: {}",epc_1!=epc_2);println!("epc_1 < epc_2: {}",epc_1<epc_2);println!("epc_2 < epc_1: {}",epc_2<epc_1);println!("epc_2 > epc_1: {}",epc_2>epc_1);println!("epc_1 <= epc_3: {}",epc_1<=epc_3);println!("epc_2 >= epc_1: {}",epc_2>=epc_1);}
importbraheasbhbh.initialize_eop()# Create an epochepc=bh.Epoch(2024,6,15,14,30,45.5,0.0)print(f"Epoch: {epc}")# Output the equivalent Julian Datejd=epc.jd()print(f"Julian Date: {jd:.6f}")# Get the Julian Date in a different time system (e.g., TT)jd_tt=epc.jd_as_time_system(time_system=bh.TT)print(f"Julian Date (TT): {jd_tt:.6f}")# Output the equivalent Modified Julian Datemjd=epc.mjd()print(f"Modified Julian Date: {mjd:.6f}")# Get the Modified Julian Date in a different time system (e.g., GPS)mjd_gps=epc.mjd_as_time_system(time_system=bh.GPS)print(f"Modified Julian Date (GPS): {mjd_gps:.6f}")# Get the GPS Week and Seconds of Weekgps_week,gps_sow=epc.gps_date()print(f"GPS Week: {gps_week}, Seconds of Week: {gps_sow:.3f}")# The Epoch as GPS seconds since the GPS epochgps_seconds=epc.gps_seconds()print(f"GPS Seconds since epoch: {gps_seconds:.3f}")
usebraheasbh;fnmain(){bh::initialize_eop().unwrap();// Create an epochletepc=bh::Epoch::from_datetime(2024,6,15,14,30,45.5,0.0,bh::TimeSystem::UTC);println!("Epoch: {}",epc);// Output the equivalent Julian Dateletjd=epc.jd();println!("Julian Date: {:.6}",jd);// Get the Julian Date in a different time system (e.g., TT)letjd_tt=epc.jd_as_time_system(bh::TimeSystem::TT);println!("Julian Date (TT): {:.6}",jd_tt);// Output the equivalent Modified Julian Dateletmjd=epc.mjd();println!("Modified Julian Date: {:.6}",mjd);// Get the Modified Julian Date in a different time system (e.g., GPS)letmjd_gps=epc.mjd_as_time_system(bh::TimeSystem::GPS);println!("Modified Julian Date (GPS): {:.6}",mjd_gps);// Get the GPS Week and Seconds of Weeklet(gps_week,gps_sow)=epc.gps_date();println!("GPS Week: {}, Seconds of Week: {:.3}",gps_week,gps_sow);// The Epoch as GPS seconds since the GPS epochletgps_seconds=epc.gps_seconds();println!("GPS Seconds since epoch: {:.3}",gps_seconds);}
importbraheasbhbh.initialize_eop()# Create an epochepc=bh.Epoch(2024,6,15,14,30,45.123456789,0.0)# Default string representationprint(f"Default: {epc}")# Explicit string conversionprint(f"String: {str(epc)}")# Debug representationprint(f"Debug: {repr(epc)}")# Get string in a different time systemprint(f"TT: {epc.to_string_as_time_system(bh.TimeSystem.TT)}")# Get as ISO 8601 formatted stringprint(f"ISO 8601: {epc.isostring()}")# Get as ISO 8601 with different number of decimal placesprint(f"ISO 8601 (0 decimal places): {epc.isostring_with_decimals(0)}")print(f"ISO 8601 (3 decimal places): {epc.isostring_with_decimals(3)}")print(f"ISO 8601 (6 decimal places): {epc.isostring_with_decimals(6)}")
seconds_past_j2000_as_time_system returns the number of seconds elapsed since the J2000 epoch (2000-01-01 12:00:00 TT), expressed in a chosen time system. Requesting TimeSystem.TDB gives SPICE ephemeris time (ET), the time argument used by SPK/PCK kernel queries (spk_position, sun_position_spice, ...); see SPICE Kernels. spice_et() is a convenience alias for seconds_past_j2000_as_time_system(TimeSystem.TDB).
importbraheasbhbh.initialize_eop()epc=bh.Epoch.from_datetime(2025,3,15,6,30,21.0,0.0,bh.TimeSystem.UTC)# SPICE ephemeris time (ET) is TDB seconds past J2000. spk_position/velocity/state# and the *_spice functions convert epochs this way internally.et=epc.seconds_past_j2000_as_time_system(bh.TimeSystem.TDB)print(f"Epoch: {epc}")print(f"SPICE ET (TDB seconds past J2000): {et:.6f}")# Other time systems are available the same way.tt=epc.seconds_past_j2000_as_time_system(bh.TimeSystem.TT)print(f"TT seconds past J2000: {tt:.6f}")print(f"TDB - TT (s): {et-tt:.9f}")
usebraheasbh;fnmain(){bh::initialize_eop().unwrap();letepc=bh::Epoch::from_datetime(2025,3,15,6,30,21.0,0.0,bh::TimeSystem::UTC);// SPICE ephemeris time (ET) is TDB seconds past J2000. spk_position/velocity/state// and the *_spice functions convert epochs this way internally.letet=epc.seconds_past_j2000_as_time_system(bh::TimeSystem::TDB);println!("Epoch: {}",epc);println!("SPICE ET (TDB seconds past J2000): {:.6}",et);// Other time systems are available the same way.lettt=epc.seconds_past_j2000_as_time_system(bh::TimeSystem::TT);println!("TT seconds past J2000: {:.6}",tt);println!("TDB - TT (s): {:.9}",et-tt);}