https://overmt.com/yahoo-finance에서-주식-정보-가져오기-1/
의 코드 중 코드 2를 기준으로 chrono crate을 이용한 format_timestamp 함수와 tokio main 매크로에 대해 알아보겠습니다.
Ⅰ. format_timestamp 함수에 대해 알아보기
fn format_timestamp(timestamp: i64) -> String {
match Utc.timestamp_opt(timestamp, 0) {
chrono::LocalResult::Single(datetime) => datetime.format("%Y-%m-%d %H:%M:%S").to_string(),
_ => "Invalid timestamp".to_string(),
}
}
1. 입력값
timestamp: i64 : 이 값은 유닉스 타임스탬프(1970-01-01 00:00:00 UTC 기준의 초 단위 정수) 입니다.
2. Utc.timestamp_opt(timestamp, 0)
- chrono::Utc는 UTC(협정 세계시) 타임존을 나타냅니다.
- timestamp_opt(secs, nsecs)는 주어진 초(secs)와 나노초(nsecs)를 UTC 시각으로 변환하려고 시도합니다.
- 반환값은 -chrono::LocalResult> enum인데, 이에는 세 가지 경우가 있습니다.
– Single(datetime) → 정상적으로 변환됨
– None → 변환 불가
– Ambiguous(, ) → 모호한 시간 (주로 로컬 타임존에서 섬머타임 전환 시 발생, UTC에서는 거의 없음)
3. match 표현식
- chrono::LocalResult::Single(datetime)일 경우에는 변환된 datetime을 format(“%Y-%m-%d %H:%M:%S”)로 지정한 문자열 포맷(연-월-일 시:분:초)으로 변환하고,
- 그 밖의 경우(None, Ambiguous)는 “Invalid timestamp”라는 문자열을 반환합니다.
Ⅱ. tokio main 매크로에 대해 알아보기
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let symbols = [
"005930.KS", // 삼성전자
"AAPL", // Apple
"TSLA", // Tesla
"LIT", // Global X Lithium & Battery Tech ETF
"BRK-B", // Berkshire Hathaway Class B
"AMZN", // Amazon
"O", // Realty Income Corporation
"TQQQ", // ProShares UltraPro QQQ
"XOM", // Exxon Mobil
"WMT", // Walmart
];
println!("Fetching stock data...\n");
let results = fetch_multiple_stocks(&symbols).await;
// 테이블 헤더 출력
println!("{:<3} {:<10} {:<35} {:<15} {:<8} {:<20}",
"No.", "Symbol", "Long Name", "Regular Price", "Currency", "Regular Market Time");
println!("{}", "-".repeat(95));
for (i, result) in results.iter().enumerate() {
let row_number = i + 1;
match result {
Ok(stock) => {
println!("{:<3} {:<10} {:<35} {:<15.2} {:<8} {:<20}",
row_number,
stock.symbol,
if stock.long_name.len() > 35 {
format!("{}...", &stock.long_name[..32])
} else {
stock.long_name.clone()
},
stock.regular_market_price,
stock.currency,
format_timestamp(stock.regular_market_time)
);
}
Err(e) => {
println!("{:<3} {:<10} {:<35} {:<15} {:<8} {:<20}",
row_number,
symbols[i],
"Error fetching data",
"N/A",
"N/A",
"N/A"
);
}
}
}
Ok(())
}
1. Tokio 런타임
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
- #[tokio::main]은 Tokio 비동기 런타임을 사용하는 매크로.
- async fn main() → 메인 함수 자체가 비동기 함수로 실행됨.
- 반환 타입이 Result<(), Box<dyn std::error::Error + Send + Sync>>으로서 성공했을 때는 (), 다시 말해 빈 튜플을 반환하므로 아무 값도 안돌려주고, 오류가 발생했을 때 다양한 에러 타입을 동적으로 담아 반환합니다.
2. 주식 심볼 배열
let symbols = [
"005930.KS", // 삼성전자
"AAPL", // Apple
"TSLA", // Tesla
"LIT", // Global X Lithium & Battery Tech ETF
"BRK-B", // Berkshire Hathaway Class B
"AMZN", // Amazon
"O", // Realty Income Corporation
"TQQQ", // ProShares UltraPro QQQ
"XOM", // Exxon Mobil
"WMT", // Walmart
];
- fetch_multiple_stocks함수의 인수로 전달하기 위해 여러 주식의 티커(symbol)를 배열로 정의합니다.
3. 주식 데이터 가져오기
println!("Fetching stock data...\n");
let results = fetch_multiple_stocks(&symbols).await;
- “Fetching stock data…” → 데이터 가져오기 시작 알림 출력.
- fetch_multiple_stocks 함수는 비동기 함수로, 각 심볼에 대해 API 호출을 시도하여 Vec<Result<StockData, Error>> 를 반환함
4. 표 헤더 출력
println!("{:<3} {:<10} {:<35} {:<15} {:<8} {:<20}",
"No.", "Symbol", "Long Name", "Regular Price", "Currency", "Regular Market Time");
println!("{}", "-".repeat(95));
- {:<n} 포맷은 왼쪽 정렬(Left Align) 하여 n 자리 확보.
- 따라서 표 형태로 깔끔하게 정렬됨.
- 이어서 “-“.repeat(95)로 구분선 출력.
5. 각 결과 출력
for (i, result) in results.iter().enumerate() {
let row_number = i + 1;
match result {
Ok(stock) => {
println!("{:<3} {:<10} {:<35} {:<15.2} {:<8} {:<20}",
row_number,
stock.symbol,
if stock.long_name.len() > 35 {
format!("{}...", &stock.long_name[..32])
} else {
stock.long_name.clone()
},
stock.regular_market_price,
stock.currency,
format_timestamp(stock.regular_market_time)
);
}
Err(e) => {
println!("{:<3} {:<10} {:<35} {:<15} {:<8} {:<20}",
row_number,
symbols[i],
"Error fetching data",
"N/A",
"N/A",
"N/A"
);
}
}
}
- enumerate()를 쓰면 (index, result) 튜플이 넘어옴. row_number = i + 1로 1씩 증가하는 번호를 출력.
- match result:
① 성공(Ok(stock))하면
– stock(StockData 구조체)를 이용해 주식 데이터를 출력하는데, stock은 result가 성공했을 때 값입니다.
– stock.symbol 값을 symbol로 출력하고,
– stock.long_name은 너무 길면 앞의 32자만 출력하고, + “…” 붙여서 가독성을 유지하고,
– stock.regular_market_price는 소수점 둘째 자리까지 표시하고,({:.2}),
– 화폐 단위(currency)를 출력하고,
– stock.regular_market_time은 format_timestamp 함수로 변환하여 표시함
② 실패(Err)하면
– 주어진 symbols[i] 심볼과 함께 “Error fetching data”, “N/A” 값들을 표시.
- match result:
6. 종료
Ok(())
- main 함수가 정상 종료됨을 의미.