time.md
429 lines · skills/astropy/references/time.md at 5f2bc03
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
Raw lines 5 to 6Basic 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')Raw lines 7 to 29Array 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')Raw lines 30 to 41Time Formats
Raw lines 42 to 43Supported 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)Raw lines 44 to 80Time Scales
Raw lines 81 to 82Available 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')Raw lines 83 to 107Converting 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
# These are the same instant, so their elapsed-time difference is zero.
print((t.tai - t.utc).sec) # 0.0
print(t.utc.iso, t.tai.iso) # 12:00:00 UTC and 12:00:37 TAI on this date
# UTC contains leap seconds: this wall-clock interval spans two SI seconds.
before = Time("2016-12-31 23:59:59", scale="utc")
after = Time("2017-01-01 00:00:00", scale="utc")
print((after - before).to_value(u.s)) # approximately 2Raw lines 108 to 128Format Conversions
Raw lines 129 to 130Change 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 MJDRaw lines 131 to 148High-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 representationRaw lines 149 to 158Time Arithmetic
Raw lines 159 to 160TimeDelta 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 secondsRaw lines 161 to 177Adding/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.weekA u.day is 86400 SI seconds and a u.year is a Julian year; neither guarantees a fixed local wall-clock hour across UTC leap seconds or DST.
Time Ranges
# Create range of times
start = Time('2023-01-01', scale='utc')
end = Time('2023-12-31', scale='utc')
times = start + np.linspace(0, 1, 100) * (end - start)
# This includes both endpoints; 365 days after Jan 1 would reach Jan 1, 2024.Raw lines 198 to 207Observing-Related Features
Some high-precision time and coordinate operations use IERS Earth-rotation data. Astropy uses astropy-iers-data by default, but may auto-download fresher IERS-A data when required for UT1 or polar-motion values. Disable auto-download for offline or privacy-sensitive runs:
from astropy.utils import iers
iers.conf.auto_download = FalseRaw lines 208 to 217Sidereal 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}")Raw lines 218 to 235Light Travel Time Corrections
from astropy.coordinates import SkyCoord, EarthLocation
# Define target and observer
target = SkyCoord(ra=10*u.deg, dec=20*u.deg)
# Synthetic site for a self-contained example; use surveyed coordinates in research.
location = EarthLocation(lat=40*u.deg, lon=-120*u.deg, height=1000*u.m)
# Observation times
times = Time(['2023-01-01', '2023-06-01', '2023-12-31'],
location=location, scale='utc')
# 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_baryRaw lines 236 to 257Earth Rotation Angle
# Earth rotation angle (for celestial to terrestrial transformations)
era = t.earth_rotation_angle()For reproducible barycentric times, record the input scale, site, target frame/epoch and ephemeris (builtin is the default). BJD_TDB is a barycentric corrected time, not just Time.utc displayed as JD. External JPL ephemerides may require downloads. The RV helper returns an optical-convention correction; for precision optical RVs use rv + correction + rv*correction/c and document the convention.
Handling Missing or Invalid Times
Raw lines 271 to 272Masked 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]
# Drop missing rows; .unmasked merely removes the mask and exposes stored values.
times_clean = times[~times.mask]
# Fill masked values
times_filled = times.filled(Time('2000-01-01'))Raw lines 273 to 291Time Precision and Representation
Raw lines 292 to 293Internal 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
# Two-part representation preserves precision; accuracy still depends on inputs.Raw lines 294 to 306Precision
# 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 throughoutRaw lines 307 to 317Time Formatting
Raw lines 318 to 319Custom 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'Raw lines 320 to 334Common Use Cases
Raw lines 335 to 336Converting 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.isoRaw lines 337 to 352Time 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)}")Raw lines 353 to 365Creating 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.secondRaw lines 366 to 381Time Zone Handling
# UTC to local time (requires datetime)
t = Time('2023-01-15 12:00:00', scale='utc')
dt_utc = t.to_datetime()
# Standard-library timezone conversion; datetime cannot represent leap seconds.
from datetime import timezone
from zoneinfo import ZoneInfo
dt_eastern = t.to_datetime(timezone=timezone.utc).astimezone(ZoneInfo("America/New_York"))Raw lines 382 to 394Barycentric Correction Example
from astropy.coordinates import SkyCoord, EarthLocation
# Target coordinates
target = SkyCoord(ra='23h23m08.55s', dec='+18d24m59.3s')
# Observatory location
# Synthetic site for a self-contained example; use surveyed coordinates in research.
location = EarthLocation(lat=40*u.deg, lon=-120*u.deg, height=1000*u.m)
# Observation times (must include location)
times = Time(['2023-01-15 08:30:00', '2023-01-16 08:30:00'],
location=location, scale='utc')
# 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 work, use the coordinate helper instead
# times already carries the observer location: do not supply it a second time.
rv_correction = target.radial_velocity_correction(obstime=times)Raw lines 395 to 421Performance Considerations
- Array operations are fast: Process multiple times as arrays
- Format conversions are cached: Repeated access is efficient
- Scale conversions may require IERS data: Update
astropy-iers-databefore offline runs, or setiers.conf.auto_download = Falseto prevent network access - Precision is not accuracy: Input timestamps, leap seconds, IERS, ephemerides and observatory/target coordinates bound physical accuracy. Preserve
jd1,jd2, scale and location when serializing precise times; a single float JD loses precision.