Initial commit
This commit is contained in:
404
skills/astropy/references/time.md
Normal file
404
skills/astropy/references/time.md
Normal file
@@ -0,0 +1,404 @@
|
||||
# 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
|
||||
|
||||
```python
|
||||
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
|
||||
|
||||
```python
|
||||
# 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
|
||||
|
||||
```python
|
||||
# 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
|
||||
|
||||
```python
|
||||
# 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
|
||||
|
||||
```python
|
||||
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
|
||||
|
||||
```python
|
||||
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
|
||||
|
||||
```python
|
||||
# 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
|
||||
|
||||
```python
|
||||
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
|
||||
|
||||
```python
|
||||
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
|
||||
|
||||
```python
|
||||
# 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')
|
||||
```
|
||||
|
||||
## Observing-Related Features
|
||||
|
||||
### Sidereal Time
|
||||
|
||||
```python
|
||||
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
|
||||
|
||||
```python
|
||||
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
|
||||
|
||||
```python
|
||||
# Earth rotation angle (for celestial to terrestrial transformations)
|
||||
era = t.earth_rotation_angle()
|
||||
```
|
||||
|
||||
## Handling Missing or Invalid Times
|
||||
|
||||
### Masked Times
|
||||
|
||||
```python
|
||||
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:
|
||||
|
||||
```python
|
||||
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
|
||||
|
||||
```python
|
||||
# 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
|
||||
|
||||
```python
|
||||
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
|
||||
|
||||
```python
|
||||
# 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
|
||||
|
||||
```python
|
||||
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
|
||||
|
||||
```python
|
||||
# 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
|
||||
|
||||
```python
|
||||
# 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
|
||||
|
||||
```python
|
||||
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
|
||||
Reference in New Issue
Block a user