Files
2025-11-30 08:30:10 +08:00

8.9 KiB

Time Handling (astropy.time)

The astropy.time module provides robust tools for manipulating times and dates with support for various time scales and formats.

Creating Time Objects

Basic Creation

from astropy.time import Time
import astropy.units as u

# ISO format (automatically detected)
t = Time('2023-01-15 12:30:45')
t = Time('2023-01-15T12:30:45')

# Specify format explicitly
t = Time('2023-01-15 12:30:45', format='iso', scale='utc')

# Julian Date
t = Time(2460000.0, format='jd')

# Modified Julian Date
t = Time(59945.0, format='mjd')

# Unix time (seconds since 1970-01-01)
t = Time(1673785845.0, format='unix')

Array of Times

# Multiple times
times = Time(['2023-01-01', '2023-06-01', '2023-12-31'])

# From arrays
import numpy as np
jd_array = np.linspace(2460000, 2460100, 100)
times = Time(jd_array, format='jd')

Time Formats

Supported Formats

# ISO 8601
t = Time('2023-01-15 12:30:45', format='iso')
t = Time('2023-01-15T12:30:45.123', format='isot')

# Julian dates
t = Time(2460000.0, format='jd')          # Julian Date
t = Time(59945.0, format='mjd')           # Modified Julian Date

# Decimal year
t = Time(2023.5, format='decimalyear')
t = Time(2023.5, format='jyear')          # Julian year
t = Time(2023.5, format='byear')          # Besselian year

# Year and day-of-year
t = Time('2023:046', format='yday')       # 46th day of 2023

# FITS format
t = Time('2023-01-15T12:30:45', format='fits')

# GPS seconds
t = Time(1000000000.0, format='gps')

# Unix time
t = Time(1673785845.0, format='unix')

# Matplotlib dates
t = Time(738521.0, format='plot_date')

# datetime objects
from datetime import datetime
dt = datetime(2023, 1, 15, 12, 30, 45)
t = Time(dt)

Time Scales

Available Time Scales

# UTC - Coordinated Universal Time (default)
t = Time('2023-01-15 12:00:00', scale='utc')

# TAI - International Atomic Time
t = Time('2023-01-15 12:00:00', scale='tai')

# TT - Terrestrial Time
t = Time('2023-01-15 12:00:00', scale='tt')

# TDB - Barycentric Dynamical Time
t = Time('2023-01-15 12:00:00', scale='tdb')

# TCG - Geocentric Coordinate Time
t = Time('2023-01-15 12:00:00', scale='tcg')

# TCB - Barycentric Coordinate Time
t = Time('2023-01-15 12:00:00', scale='tcb')

# UT1 - Universal Time
t = Time('2023-01-15 12:00:00', scale='ut1')

Converting Time Scales

t = Time('2023-01-15 12:00:00', scale='utc')

# Convert to different scales
t_tai = t.tai
t_tt = t.tt
t_tdb = t.tdb
t_ut1 = t.ut1

# Check offset
print(f"TAI - UTC = {(t.tai - t.utc).sec} seconds")
# TAI - UTC = 37 seconds (leap seconds)

Format Conversions

Change Output Format

t = Time('2023-01-15 12:30:45')

# Access in different formats
print(t.jd)           # Julian Date
print(t.mjd)          # Modified Julian Date
print(t.iso)          # ISO format
print(t.isot)         # ISO with 'T'
print(t.unix)         # Unix time
print(t.decimalyear)  # Decimal year

# Change default format
t.format = 'mjd'
print(t)  # Displays as MJD

High-Precision Output

# Use subfmt for precision control
t.to_value('mjd', subfmt='float')    # Standard float
t.to_value('mjd', subfmt='long')     # Extended precision
t.to_value('mjd', subfmt='decimal')  # Decimal (highest precision)
t.to_value('mjd', subfmt='str')      # String representation

Time Arithmetic

TimeDelta Objects

from astropy.time import TimeDelta

# Create time difference
dt = TimeDelta(1.0, format='jd')      # 1 day
dt = TimeDelta(3600.0, format='sec')  # 1 hour

# Subtract times
t1 = Time('2023-01-15')
t2 = Time('2023-02-15')
dt = t2 - t1
print(dt.jd)   # 31 days
print(dt.sec)  # 2678400 seconds

Adding/Subtracting Time

t = Time('2023-01-15 12:00:00')

# Add TimeDelta
t_future = t + TimeDelta(7, format='jd')  # Add 7 days

# Add Quantity
t_future = t + 1*u.hour
t_future = t + 30*u.day
t_future = t + 1*u.year

# Subtract
t_past = t - 1*u.week

Time Ranges

# Create range of times
start = Time('2023-01-01')
end = Time('2023-12-31')
times = start + np.linspace(0, 365, 100) * u.day

# Or using TimeDelta
times = start + TimeDelta(np.linspace(0, 365, 100), format='jd')

Sidereal Time

from astropy.coordinates import EarthLocation

# Define observer location
location = EarthLocation(lat=40*u.deg, lon=-120*u.deg, height=1000*u.m)

# Create time with location
t = Time('2023-06-15 23:00:00', location=location)

# Calculate sidereal time
lst_apparent = t.sidereal_time('apparent')
lst_mean = t.sidereal_time('mean')

print(f"Local Sidereal Time: {lst_apparent}")

Light Travel Time Corrections

from astropy.coordinates import SkyCoord, EarthLocation

# Define target and observer
target = SkyCoord(ra=10*u.deg, dec=20*u.deg)
location = EarthLocation.of_site('Keck Observatory')

# Observation times
times = Time(['2023-01-01', '2023-06-01', '2023-12-31'],
             location=location)

# Calculate light travel time to solar system barycenter
ltt_bary = times.light_travel_time(target, kind='barycentric')
ltt_helio = times.light_travel_time(target, kind='heliocentric')

# Apply correction
times_barycentric = times.tdb + ltt_bary

Earth Rotation Angle

# Earth rotation angle (for celestial to terrestrial transformations)
era = t.earth_rotation_angle()

Handling Missing or Invalid Times

Masked Times

import numpy as np

# Create times with missing values
times = Time(['2023-01-01', '2023-06-01', '2023-12-31'])
times[1] = np.ma.masked  # Mark as missing

# Check for masks
print(times.mask)  # [False True False]

# Get unmasked version
times_clean = times.unmasked

# Fill masked values
times_filled = times.filled(Time('2000-01-01'))

Time Precision and Representation

Internal Representation

Time objects use two 64-bit floats (jd1, jd2) for high precision:

t = Time('2023-01-15 12:30:45.123456789', format='iso', scale='utc')

# Access internal representation
print(t.jd1, t.jd2)  # Integer and fractional parts

# This allows sub-nanosecond precision over astronomical timescales

Precision

# High precision for long time intervals
t1 = Time('1900-01-01')
t2 = Time('2100-01-01')
dt = t2 - t1
print(f"Time span: {dt.sec / (365.25 * 86400)} years")
# Maintains precision throughout

Time Formatting

Custom String Format

t = Time('2023-01-15 12:30:45')

# Strftime-style formatting
t.strftime('%Y-%m-%d %H:%M:%S')  # '2023-01-15 12:30:45'
t.strftime('%B %d, %Y')          # 'January 15, 2023'

# ISO format subformats
t.iso                    # '2023-01-15 12:30:45.000'
t.isot                   # '2023-01-15T12:30:45.000'
t.to_value('iso', subfmt='date_hms')  # '2023-01-15 12:30:45.000'

Common Use Cases

Converting Between Formats

# MJD to ISO
t_mjd = Time(59945.0, format='mjd')
iso_string = t_mjd.iso

# ISO to JD
t_iso = Time('2023-01-15 12:00:00')
jd_value = t_iso.jd

# Unix to ISO
t_unix = Time(1673785845.0, format='unix')
iso_string = t_unix.iso

Time Differences in Various Units

t1 = Time('2023-01-01')
t2 = Time('2023-12-31')

dt = t2 - t1
print(f"Days: {dt.to(u.day)}")
print(f"Hours: {dt.to(u.hour)}")
print(f"Seconds: {dt.sec}")
print(f"Years: {dt.to(u.year)}")

Creating Regular Time Series

# Daily observations for a year
start = Time('2023-01-01')
times = start + np.arange(365) * u.day

# Hourly observations for a day
start = Time('2023-01-15 00:00:00')
times = start + np.arange(24) * u.hour

# Observations every 30 seconds
start = Time('2023-01-15 12:00:00')
times = start + np.arange(1000) * 30 * u.second

Time Zone Handling

# UTC to local time (requires datetime)
t = Time('2023-01-15 12:00:00', scale='utc')
dt_utc = t.to_datetime()

# Convert to specific timezone using pytz
import pytz
eastern = pytz.timezone('US/Eastern')
dt_eastern = dt_utc.replace(tzinfo=pytz.utc).astimezone(eastern)

Barycentric Correction Example

from astropy.coordinates import SkyCoord, EarthLocation

# Target coordinates
target = SkyCoord(ra='23h23m08.55s', dec='+18d24m59.3s')

# Observatory location
location = EarthLocation.of_site('Keck Observatory')

# Observation times (must include location)
times = Time(['2023-01-15 08:30:00', '2023-01-16 08:30:00'],
             location=location)

# Calculate barycentric correction
ltt_bary = times.light_travel_time(target, kind='barycentric')

# Apply correction to get barycentric times
times_bary = times.tdb + ltt_bary

# For radial velocity correction
rv_correction = ltt_bary.to(u.km, equivalencies=u.dimensionless_angles())

Performance Considerations

  1. Array operations are fast: Process multiple times as arrays
  2. Format conversions are cached: Repeated access is efficient
  3. Scale conversions may require IERS data: Downloads automatically
  4. High precision maintained: Sub-nanosecond accuracy across astronomical timescales