如何让React天气App根据搜索城市切换对应时区时间?
解决React天气App中根据城市切换时区时间的问题
我正在使用OpenWeatherAPI开发一款React天气App,目前已成功显示当前时间,但不清楚如何实现根据搜索的城市切换对应时区的时间,附上当前实现代码,尝试过不少方案但均未成功,或是未能理解解决方案。
function App() { const [query, setQuery] = useState(''); const [weather, setWeather] = useState({}); const search = evt => { if (evt.key === "Enter") { fetch(`${api.base}weather?q=${query}&units=metric&APPID=${api.key}`) .then(res => res.json()) .then(result => { setWeather(result); setQuery(''); console.log(result); }); } } const dateBuilder = (d) => { let months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]; let days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]; let day = days[d.getDay()]; let date = d.getDate(); let month = months[d.getMonth()]; let year = d.getFullYear(); return `${day} ${date} ${month} ${year}` } const time = (date) => { let hours = date.getHours(); let minutes = date.getMinutes(); return `${hours} : ${minutes} ` } return ( <div className={(typeof weather.weather != "undefined") ? ((weather.weather[0].main === "Clear") ? 'app warm' : (weather.weather[0].main === "Thunderstorm") ? 'app thunderstorm' : (weather.weather[0].main === "Snow") ? 'app snow' : (weather.weather[0].main === "Clouds") ? 'app clouds' : (weather.weather[0].main === "Rain") ? 'app rain' : (weather.weather[0].main === "Drizzle") ? 'app drizzle' : 'app') : 'app'}> <main> <div className="search-box"> <input type="text" className="search-bar" placeholder="Search City..." onChange={e => setQuery(e.target.value)} value={query} onKeyPress={search} /> </div> {(typeof weather.main != "undefined") ? ( <div> <div className="location-box"> <div className="location">{weather.name}, {weather.sys.country}</div> <div className="date">{dateBuilder(new Date())}</div> </div> <div className="weather-box"> <div className="temp"> {Math.round(weather.main.temp)}°c </div> <div className="weather">{weather.weather[0].main}</div> <div className="time">{time(new Date())}</div> </div> </div> ) : ('')} </main> </div> ); } export default App;
解决方案
OpenWeatherAPI的weather接口会返回目标城市的timezone字段,该值是城市时间相对于UTC的偏移秒数(比如北京为28800,即8小时)。我们可以利用这个值计算出目标城市的当地时间,避免本地时区的干扰。
1. 修改时间/日期生成函数
将dateBuilder和time函数修改为接收时区偏移量参数,基于UTC时间计算当地时间:
const dateBuilder = (timezoneOffset) => { const now = new Date(); // 计算当地时间:UTC时间 + 时区偏移秒数 const localDate = new Date(now.getTime() + timezoneOffset * 1000); const months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]; const days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]; const day = days[localDate.getUTCDay()]; const date = localDate.getUTCDate(); const month = months[localDate.getUTCMonth()]; const year = localDate.getUTCFullYear(); return `${day} ${date} ${month} ${year}`; }; const time = (timezoneOffset) => { const now = new Date(); const localDate = new Date(now.getTime() + timezoneOffset * 1000); let hours = localDate.getUTCHours(); let minutes = localDate.getUTCMinutes(); // 补零处理,优化显示格式 hours = hours.toString().padStart(2, '0'); minutes = minutes.toString().padStart(2, '0'); return `${hours}:${minutes}`; };
2. 渲染时传入时区偏移量
在JSX渲染部分,调用函数时传入weather.timezone:
<div className="location-box"> <div className="location">{weather.name}, {weather.sys.country}</div> <div className="date">{dateBuilder(weather.timezone)}</div> </div> <div className="weather-box"> <div className="temp"> {Math.round(weather.main.temp)}°c </div> <div className="weather">{weather.weather[0].main}</div> <div className="time">{time(weather.timezone)}</div> </div>
3. 完整修改后的代码
function App() { const [query, setQuery] = useState(''); const [weather, setWeather] = useState({}); const search = evt => { if (evt.key === "Enter") { fetch(`${api.base}weather?q=${query}&units=metric&APPID=${api.key}`) .then(res => res.json()) .then(result => { setWeather(result); setQuery(''); console.log(result); }); } } const dateBuilder = (timezoneOffset) => { const now = new Date(); const localDate = new Date(now.getTime() + timezoneOffset * 1000); const months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]; const days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]; const day = days[localDate.getUTCDay()]; const date = localDate.getUTCDate(); const month = months[localDate.getUTCMonth()]; const year = localDate.getUTCFullYear(); return `${day} ${date} ${month} ${year}`; }; const time = (timezoneOffset) => { const now = new Date(); const localDate = new Date(now.getTime() + timezoneOffset * 1000); let hours = localDate.getUTCHours(); let minutes = localDate.getUTCMinutes(); hours = hours.toString().padStart(2, '0'); minutes = minutes.toString().padStart(2, '0'); return `${hours}:${minutes}`; }; return ( <div className={(typeof weather.weather != "undefined") ? ((weather.weather[0].main === "Clear") ? 'app warm' : (weather.weather[0].main === "Thunderstorm") ? 'app thunderstorm' : (weather.weather[0].main === "Snow") ? 'app snow' : (weather.weather[0].main === "Clouds") ? 'app clouds' : (weather.weather[0].main === "Rain") ? 'app rain' : (weather.weather[0].main === "Drizzle") ? 'app drizzle' : 'app') : 'app'}> <main> <div className="search-box"> <input type="text" className="search-bar" placeholder="Search City..." onChange={e => setQuery(e.target.value)} value={query} onKeyPress={search} /> </div> {(typeof weather.main != "undefined") ? ( <div> <div className="location-box"> <div className="location">{weather.name}, {weather.sys.country}</div> <div className="date">{dateBuilder(weather.timezone)}</div> </div> <div className="weather-box"> <div className="temp"> {Math.round(weather.main.temp)}°c </div> <div className="weather">{weather.weather[0].main}</div> <div className="time">{time(weather.timezone)}</div> </div> </div> ) : ('')} </main> </div> ); } export default App;
内容的提问来源于stack exchange,提问作者Matthew L
相关产品推荐
相关产品推荐

