Building Daily Panchang Features with Vedic Astrology API
Complete guide to implementing Tithi, Nakshatra, Yoga, and Karana calculations. Includes location-based timings, muhurat selection, and auspicious period detection.
Building Daily Panchang Features with Vedic Astrology API
Daily Panchang is the cornerstone of Vedic timekeeping, used by millions across India to plan important activities, ceremonies, and daily routines. Whether you are building a spiritual wellness app, astrology platform, or calendar application, implementing accurate Panchang features can significantly boost user engagement and retention.
This comprehensive guide shows you how to build production-ready daily Panchang features using the RoxyAPI Vedic Astrology API, complete with location-based calculations, auspicious period detection, and personalized muhurat recommendations.
What We Will Build
Our Panchang feature includes:
- Daily Panchang Display - Tithi, Nakshatra, Yoga, Karana with timings
- Location-Based Calculations - Sunrise, sunset, moonrise, moonset for any location
- Auspicious Period Detection - Automatically identify good muhurats
- Inauspicious Period Alerts - Rahu Kaal, Yamaghanta, Gulika Kaal
- Monthly Calendar View - All Panchang elements for the month
- Push Notifications - Daily Panchang alerts at sunrise
- Muhurat Recommendations - Personalized timing suggestions for activities
- Festival Integration - Hindu festivals and observances
Understanding Panchang Components
Panchang consists of five (Pancha) limbs (Anga):
1. Tithi (Lunar Day)
30 Tithis in a lunar month, divided into two pakshas:
Shukla Paksha (Waxing Moon):
- Pratipada (1st)
- Dvitiya (2nd)
- Tritiya (3rd)
- Chaturthi (4th)
- Panchami (5th)
- Shashthi (6th)
- Saptami (7th)
- Ashtami (8th)
- Navami (9th)
- Dashami (10th)
- Ekadashi (11th)
- Dwadashi (12th)
- Trayodashi (13th)
- Chaturdashi (14th)
- Purnima (Full Moon)
Krishna Paksha (Waning Moon): 1-14 same names, ending with Amavasya (New Moon)
2. Nakshatra (Lunar Mansion)
27 constellations spanning 13°20' each. Each has unique characteristics:
- Ashwini - Swift, healing
- Bharani - Restraint, discipline
- Krittika - Sharp, cutting
- Rohini - Growth, beauty (most auspicious)
- Mrigashira - Searching, gentle
- Pushya - Nourishing (highly auspicious)
- Revati - Completion, prosperity
3. Yoga
27 yogas based on combined Sun-Moon longitudes. Examples:
- Vishkambha - Obstructions
- Siddhi - Success, accomplishment (auspicious)
- Shubha - Good fortune (auspicious)
- Amrita - Nectar, immortality (very auspicious)
4. Karana
Half of a Tithi. 11 Karanas total (7 movable, 4 fixed):
Char Karanas (Movable): Bava, Balava, Kaulava, Taitila, Garija, Vanija, Vishti Sthir Karanas (Fixed): Shakuni, Chatushpada, Naga, Kimstughna
5. Vara (Weekday)
Sunday through Saturday, each ruled by a planet.
Step 1: Basic Panchang API Integration
Set up the daily Panchang endpoint:
// lib/panchang-api.ts
interface PanchangParams {
year: number;
month: number;
day: number;
hour: number;
latitude: number;
longitude: number;
}
interface TithiInfo {
number: number;
name: string;
paksha: 'Shukla Paksha' | 'Krishna Paksha';
completion: number;
deity: string;
element: string;
characteristics: string;
auspicious: boolean;
}
interface NakshatraInfo {
number: number;
name: string;
lord: string;
deity: string;
symbol: string;
characteristics: string;
auspicious: boolean;
}
interface YogaInfo {
number: number;
name: string;
completion: number;
characteristics: string;
auspicious: boolean;
}
interface KaranaInfo {
number: number;
name: string;
type: 'char' | 'sthir';
completion: number;
characteristics: string;
auspicious: boolean;
}
interface PanchangResponse {
tithi: TithiInfo;
nakshatra: NakshatraInfo;
yoga: YogaInfo;
karana: KaranaInfo;
sunLongitude: number;
moonLongitude: number;
sunrise: string;
sunset: string;
moonrise: string;
moonset: string;
rahuKaal?: {
start: string;
end: string;
};
yamaghanta?: {
start: string;
end: string;
};
gulikaKaal?: {
start: string;
end: string;
};
}
const API_BASE = 'http://localhost:3001/api/v2/vedic-astrology';
const API_KEY = 'your_api_key_here';
export async function getDailyPanchang(
date: Date,
latitude: number,
longitude: number
): Promise<PanchangResponse> {
const response = await fetch(`${API_BASE}/panchang/basic`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': API_KEY,
},
body: JSON.stringify({
year: date.getFullYear(),
month: date.getMonth() + 1,
day: date.getDate(),
hour: date.getHours() + date.getMinutes() / 60,
latitude,
longitude,
}),
});
if (!response.ok) {
throw new Error(`Panchang API error: ${response.statusText}`);
}
return response.json();
}
Example API Response
{
"tithi": {
"number": 2,
"name": "Dvītiyā",
"paksha": "Shukla Paksha",
"completion": 38.94,
"deity": "Vidhāṭṛ",
"element": "Earth",
"characteristics": "Good for agriculture, ceremonies, construction",
"auspicious": true
},
"nakshatra": {
"number": 8,
"name": "Pushya",
"lord": "Saturn",
"deity": "Brihaspati",
"symbol": "Cow's Udder",
"characteristics": "Most auspicious, nurturing, disciplined, protectors",
"auspicious": true
},
"yoga": {
"number": 15,
"name": "Vajra",
"completion": 58.91,
"characteristics": "Power Burst - wealthy, lascivious, changeable, forceful",
"auspicious": false
},
"karana": {
"number": 3,
"name": "Kaulav",
"type": "char",
"completion": 77.88,
"characteristics": "Very friendly, talents like love and caring",
"auspicious": true
},
"sunLongitude": 88.924,
"moonLongitude": 105.597,
"sunrise": "07:15:23",
"sunset": "17:42:18",
"moonrise": "09:32:45",
"moonset": "20:18:12",
"rahuKaal": {
"start": "15:28:00",
"end": "16:52:00"
},
"yamaghanta": {
"start": "10:30:00",
"end": "11:45:00"
},
"gulikaKaal": {
"start": "13:15:00",
"end": "14:40:00"
}
}
Step 2: Daily Panchang UI Component
Build an attractive daily display:
// components/DailyPanchang.tsx
import React, { useEffect, useState } from 'react';
import { View, Text, ScrollView, StyleSheet, RefreshControl } from 'react-native';
interface Props {
latitude: number;
longitude: number;
date?: Date;
}
export function DailyPanchang({ latitude, longitude, date = new Date() }: Props) {
const [panchang, setPanchang] = useState<PanchangResponse | null>(null);
const [loading, setLoading] = useState(true);
const [refreshing, setRefreshing] = useState(false);
useEffect(() => {
loadPanchang();
}, [date, latitude, longitude]);
async function loadPanchang() {
try {
const data = await getDailyPanchang(date, latitude, longitude);
setPanchang(data);
} catch (error) {
console.error('Failed to load panchang:', error);
} finally {
setLoading(false);
}
}
async function onRefresh() {
setRefreshing(true);
await loadPanchang();
setRefreshing(false);
}
if (loading) return <Text>Loading Panchang...</Text>;
if (!panchang) return <Text>Failed to load Panchang</Text>;
return (
<ScrollView
style={styles.container}
refreshControl={
<RefreshControl refreshing={refreshing} onRefresh={onRefresh} />
}
>
{/* Header */}
<View style={styles.header}>
<Text style={styles.headerTitle}>Daily Panchang</Text>
<Text style={styles.headerDate}>
{date.toLocaleDateString('en-IN', {
weekday: 'long',
year: 'numeric',
month: 'long',
day: 'numeric',
})}
</Text>
</View>
{/* Sunrise/Sunset Times */}
<View style={styles.timesCard}>
<View style={styles.timeItem}>
<Text style={styles.timeIcon}>🌅</Text>
<View>
<Text style={styles.timeLabel}>Sunrise</Text>
<Text style={styles.timeValue}>{panchang.sunrise}</Text>
</View>
</View>
<View style={styles.timeItem}>
<Text style={styles.timeIcon}>🌄</Text>
<View>
<Text style={styles.timeLabel}>Sunset</Text>
<Text style={styles.timeValue}>{panchang.sunset}</Text>
</View>
</View>
<View style={styles.timeItem}>
<Text style={styles.timeIcon}>🌙</Text>
<View>
<Text style={styles.timeLabel}>Moonrise</Text>
<Text style={styles.timeValue}>{panchang.moonrise}</Text>
</View>
</View>
<View style={styles.timeItem}>
<Text style={styles.timeIcon}>🌑</Text>
<View>
<Text style={styles.timeLabel}>Moonset</Text>
<Text style={styles.timeValue}>{panchang.moonset}</Text>
</View>
</View>
</View>
{/* Tithi */}
<View style={[styles.card, panchang.tithi.auspicious && styles.auspiciousCard]}>
<View style={styles.cardHeader}>
<Text style={styles.cardTitle}>🌙 Tithi (Lunar Day)</Text>
{panchang.tithi.auspicious && (
<View style={styles.auspiciousBadge}>
<Text style={styles.auspiciousText}>Auspicious</Text>
</View>
)}
</View>
<Text style={styles.mainValue}>{panchang.tithi.name}</Text>
<Text style={styles.subValue}>{panchang.tithi.paksha}</Text>
<View style={styles.progressContainer}>
<View style={styles.progressBar}>
<View
style={[
styles.progressFill,
{ width: `${panchang.tithi.completion}%` },
]}
/>
</View>
<Text style={styles.progressText}>{panchang.tithi.completion.toFixed(1)}% complete</Text>
</View>
<View style={styles.detailsGrid}>
<View style={styles.detailItem}>
<Text style={styles.detailLabel}>Deity</Text>
<Text style={styles.detailValue}>{panchang.tithi.deity}</Text>
</View>
<View style={styles.detailItem}>
<Text style={styles.detailLabel}>Element</Text>
<Text style={styles.detailValue}>{panchang.tithi.element}</Text>
</View>
</View>
<Text style={styles.characteristics}>{panchang.tithi.characteristics}</Text>
</View>
{/* Nakshatra */}
<View style={[styles.card, panchang.nakshatra.auspicious && styles.auspiciousCard]}>
<View style={styles.cardHeader}>
<Text style={styles.cardTitle}>⭐ Nakshatra (Lunar Mansion)</Text>
{panchang.nakshatra.auspicious && (
<View style={styles.auspiciousBadge}>
<Text style={styles.auspiciousText}>Auspicious</Text>
</View>
)}
</View>
<Text style={styles.mainValue}>{panchang.nakshatra.name}</Text>
<Text style={styles.subValue}>#{panchang.nakshatra.number} of 27</Text>
<View style={styles.detailsGrid}>
<View style={styles.detailItem}>
<Text style={styles.detailLabel}>Lord</Text>
<Text style={styles.detailValue}>{panchang.nakshatra.lord}</Text>
</View>
<View style={styles.detailItem}>
<Text style={styles.detailLabel}>Deity</Text>
<Text style={styles.detailValue}>{panchang.nakshatra.deity}</Text>
</View>
<View style={styles.detailItem}>
<Text style={styles.detailLabel}>Symbol</Text>
<Text style={styles.detailValue}>{panchang.nakshatra.symbol}</Text>
</View>
</View>
<Text style={styles.characteristics}>{panchang.nakshatra.characteristics}</Text>
</View>
{/* Yoga */}
<View style={[styles.card, panchang.yoga.auspicious && styles.auspiciousCard]}>
<View style={styles.cardHeader}>
<Text style={styles.cardTitle}>🧘 Yoga</Text>
{panchang.yoga.auspicious && (
<View style={styles.auspiciousBadge}>
<Text style={styles.auspiciousText}>Auspicious</Text>
</View>
)}
</View>
<Text style={styles.mainValue}>{panchang.yoga.name}</Text>
<Text style={styles.subValue}>#{panchang.yoga.number} of 27</Text>
<View style={styles.progressContainer}>
<View style={styles.progressBar}>
<View
style={[
styles.progressFill,
{ width: `${panchang.yoga.completion}%` },
]}
/>
</View>
<Text style={styles.progressText}>{panchang.yoga.completion.toFixed(1)}% complete</Text>
</View>
<Text style={styles.characteristics}>{panchang.yoga.characteristics}</Text>
</View>
{/* Karana */}
<View style={[styles.card, panchang.karana.auspicious && styles.auspiciousCard]}>
<View style={styles.cardHeader}>
<Text style={styles.cardTitle}>🔱 Karana (Half Tithi)</Text>
{panchang.karana.auspicious && (
<View style={styles.auspiciousBadge}>
<Text style={styles.auspiciousText}>Auspicious</Text>
</View>
)}
</View>
<Text style={styles.mainValue}>{panchang.karana.name}</Text>
<Text style={styles.subValue}>
{panchang.karana.type === 'char' ? 'Movable' : 'Fixed'} Karana
</Text>
<View style={styles.progressContainer}>
<View style={styles.progressBar}>
<View
style={[
styles.progressFill,
{ width: `${panchang.karana.completion}%` },
]}
/>
</View>
<Text style={styles.progressText}>{panchang.karana.completion.toFixed(1)}% complete</Text>
</View>
<Text style={styles.characteristics}>{panchang.karana.characteristics}</Text>
</View>
{/* Inauspicious Periods */}
<View style={styles.warningCard}>
<Text style={styles.warningTitle}>⚠️ Inauspicious Periods (Avoid Important Activities)</Text>
{panchang.rahuKaal && (
<View style={styles.warningItem}>
<Text style={styles.warningLabel}>Rahu Kaal:</Text>
<Text style={styles.warningTime}>
{panchang.rahuKaal.start} - {panchang.rahuKaal.end}
</Text>
</View>
)}
{panchang.yamaghanta && (
<View style={styles.warningItem}>
<Text style={styles.warningLabel}>Yamaghanta:</Text>
<Text style={styles.warningTime}>
{panchang.yamaghanta.start} - {panchang.yamaghanta.end}
</Text>
</View>
)}
{panchang.gulikaKaal && (
<View style={styles.warningItem}>
<Text style={styles.warningLabel}>Gulika Kaal:</Text>
<Text style={styles.warningTime}>
{panchang.gulikaKaal.start} - {panchang.gulikaKaal.end}
</Text>
</View>
)}
</View>
</ScrollView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#FFF8F0',
},
header: {
backgroundColor: '#8B4513',
padding: 24,
alignItems: 'center',
},
headerTitle: {
fontSize: 28,
fontWeight: 'bold',
color: '#FFFFFF',
marginBottom: 8,
},
headerDate: {
fontSize: 16,
color: '#F5DEB3',
},
timesCard: {
backgroundColor: '#FFFFFF',
margin: 16,
borderRadius: 16,
padding: 16,
flexDirection: 'row',
flexWrap: 'wrap',
justifyContent: 'space-around',
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 8,
elevation: 3,
},
timeItem: {
flexDirection: 'row',
alignItems: 'center',
marginBottom: 12,
width: '45%',
},
timeIcon: {
fontSize: 32,
marginRight: 12,
},
timeLabel: {
fontSize: 12,
color: '#6B7280',
marginBottom: 4,
},
timeValue: {
fontSize: 16,
fontWeight: 'bold',
color: '#4A4A4A',
},
card: {
backgroundColor: '#FFFFFF',
marginHorizontal: 16,
marginBottom: 16,
borderRadius: 16,
padding: 20,
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 8,
elevation: 3,
},
auspiciousCard: {
borderLeftWidth: 4,
borderLeftColor: '#10B981',
},
cardHeader: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
marginBottom: 16,
},
cardTitle: {
fontSize: 18,
fontWeight: 'bold',
color: '#8B4513',
},
auspiciousBadge: {
backgroundColor: '#D1FAE5',
paddingHorizontal: 12,
paddingVertical: 4,
borderRadius: 12,
},
auspiciousText: {
fontSize: 12,
fontWeight: '600',
color: '#065F46',
},
mainValue: {
fontSize: 28,
fontWeight: 'bold',
color: '#CD853F',
marginBottom: 4,
},
subValue: {
fontSize: 14,
color: '#6B7280',
marginBottom: 16,
},
progressContainer: {
marginBottom: 16,
},
progressBar: {
height: 8,
backgroundColor: '#F3F4F6',
borderRadius: 4,
overflow: 'hidden',
marginBottom: 4,
},
progressFill: {
height: '100%',
backgroundColor: '#CD853F',
},
progressText: {
fontSize: 12,
color: '#6B7280',
textAlign: 'right',
},
detailsGrid: {
flexDirection: 'row',
flexWrap: 'wrap',
marginBottom: 16,
},
detailItem: {
width: '50%',
marginBottom: 12,
},
detailLabel: {
fontSize: 12,
color: '#6B7280',
marginBottom: 4,
},
detailValue: {
fontSize: 14,
fontWeight: '600',
color: '#4A4A4A',
},
characteristics: {
fontSize: 14,
color: '#4A4A4A',
lineHeight: 20,
fontStyle: 'italic',
},
warningCard: {
backgroundColor: '#FEF2F2',
marginHorizontal: 16,
marginBottom: 24,
borderRadius: 16,
padding: 20,
borderLeftWidth: 4,
borderLeftColor: '#EF4444',
},
warningTitle: {
fontSize: 16,
fontWeight: 'bold',
color: '#991B1B',
marginBottom: 16,
},
warningItem: {
flexDirection: 'row',
justifyContent: 'space-between',
marginBottom: 12,
},
warningLabel: {
fontSize: 14,
fontWeight: '600',
color: '#7F1D1D',
},
warningTime: {
fontSize: 14,
color: '#991B1B',
},
});
Step 3: Muhurat Selection Service
Automatically detect auspicious periods:
// services/muhurat-service.ts
interface Activity {
name: string;
requiredFactors: {
tithi?: string[];
nakshatra?: string[];
yoga?: string[];
karana?: string[];
weekday?: string[];
};
avoidFactors?: {
tithi?: string[];
nakshatra?: string[];
yoga?: string[];
};
}
export class MuhuratService {
private activities: Record<string, Activity> = {
marriage: {
name: 'Marriage Ceremony',
requiredFactors: {
nakshatra: ['Rohini', 'Mrigashira', 'Uttara Phalguni', 'Hasta', 'Revati', 'Uttara Ashadha'],
tithi: ['Dvitiya', 'Tritiya', 'Panchami', 'Saptami', 'Dashami', 'Ekadashi', 'Trayodashi'],
},
avoidFactors: {
nakshatra: ['Bharani', 'Ashlesha', 'Jyeshtha', 'Moola'],
yoga: ['Vishkambha', 'Vyatipata', 'Parigha', 'Vyaghata', 'Vajra', 'Vaidhriti'],
},
},
housewarming: {
name: 'Griha Pravesh (House Warming)',
requiredFactors: {
nakshatra: ['Rohini', 'Mrigashira', 'Pushya', 'Uttara Phalguni', 'Hasta', 'Uttara Ashadha', 'Uttara Bhadrapada', 'Revati'],
tithi: ['Dvitiya', 'Tritiya', 'Panchami', 'Saptami', 'Dashami', 'Ekadashi', 'Trayodashi'],
},
},
businessStart: {
name: 'Starting New Business',
requiredFactors: {
nakshatra: ['Ashwini', 'Rohini', 'Pushya', 'Hasta', 'Anuradha', 'Revati'],
weekday: ['Wednesday', 'Thursday', 'Friday'],
},
},
education: {
name: 'Starting Education/Vidyarambha',
requiredFactors: {
nakshatra: ['Pushya', 'Hasta', 'Chitra', 'Swati', 'Shravan', 'Dhanishta', 'Revati'],
weekday: ['Wednesday', 'Thursday'],
},
},
travel: {
name: 'Starting Journey',
requiredFactors: {
nakshatra: ['Ashwini', 'Pushya', 'Hasta', 'Anuradha', 'Shravan', 'Revati'],
tithi: ['Dvitiya', 'Tritiya', 'Panchami', 'Saptami', 'Dashami', 'Ekadashi'],
},
},
vehiclePurchase: {
name: 'Vehicle Purchase',
requiredFactors: {
nakshatra: ['Ashwini', 'Rohini', 'Pushya', 'Hasta', 'Shravan', 'Revati'],
tithi: ['Dvitiya', 'Tritiya', 'Panchami', 'Saptami', 'Dashami'],
},
},
};
checkMuhurat(
activity: string,
panchang: PanchangResponse
): { suitable: boolean; score: number; reasons: string[] } {
const activityConfig = this.activities[activity];
if (!activityConfig) {
return { suitable: false, score: 0, reasons: ['Unknown activity'] };
}
let score = 0;
const reasons: string[] = [];
// Check required factors
if (activityConfig.requiredFactors.tithi) {
if (activityConfig.requiredFactors.tithi.includes(panchang.tithi.name)) {
score += 25;
reasons.push(`✅ Favorable Tithi: ${panchang.tithi.name}`);
} else {
reasons.push(`⚠️ Tithi ${panchang.tithi.name} not ideal`);
}
}
if (activityConfig.requiredFactors.nakshatra) {
if (activityConfig.requiredFactors.nakshatra.includes(panchang.nakshatra.name)) {
score += 35;
reasons.push(`✅ Auspicious Nakshatra: ${panchang.nakshatra.name}`);
} else {
reasons.push(`⚠️ Nakshatra ${panchang.nakshatra.name} not optimal`);
}
}
if (activityConfig.requiredFactors.yoga) {
if (activityConfig.requiredFactors.yoga.includes(panchang.yoga.name)) {
score += 20;
reasons.push(`✅ Favorable Yoga: ${panchang.yoga.name}`);
}
}
if (activityConfig.requiredFactors.karana) {
if (activityConfig.requiredFactors.karana.includes(panchang.karana.name)) {
score += 10;
reasons.push(`✅ Good Karana: ${panchang.karana.name}`);
}
}
// Check avoid factors
if (activityConfig.avoidFactors) {
if (activityConfig.avoidFactors.nakshatra?.includes(panchang.nakshatra.name)) {
score -= 50;
reasons.push(`❌ Avoid Nakshatra: ${panchang.nakshatra.name}`);
}
if (activityConfig.avoidFactors.yoga?.includes(panchang.yoga.name)) {
score -= 30;
reasons.push(`❌ Unfavorable Yoga: ${panchang.yoga.name}`);
}
if (activityConfig.avoidFactors.tithi?.includes(panchang.tithi.name)) {
score -= 30;
reasons.push(`❌ Avoid Tithi: ${panchang.tithi.name}`);
}
}
// General auspicious factors
if (panchang.nakshatra.name === 'Pushya' || panchang.nakshatra.name === 'Rohini') {
score += 10;
reasons.push(`✨ Highly auspicious Nakshatra`);
}
const suitable = score >= 50;
return { suitable, score: Math.max(0, Math.min(100, score)), reasons };
}
async findBestMuhurats(
activity: string,
startDate: Date,
daysToSearch: number,
latitude: number,
longitude: number
): Promise<Array<{ date: Date; score: number; panchang: PanchangResponse }>> {
const muhurats: Array<{ date: Date; score: number; panchang: PanchangResponse }> = [];
for (let i = 0; i < daysToSearch; i++) {
const date = new Date(startDate);
date.setDate(date.getDate() + i);
const panchang = await getDailyPanchang(date, latitude, longitude);
const result = this.checkMuhurat(activity, panchang);
if (result.suitable) {
muhurats.push({ date, score: result.score, panchang });
}
}
// Sort by score descending
return muhurats.sort((a, b) => b.score - a.score);
}
}
Step 4: Monthly Panchang Calendar
Display entire month at a glance:
// components/MonthlyPanchang.tsx
import React, { useEffect, useState } from 'react';
import { View, Text, ScrollView, StyleSheet, TouchableOpacity } from 'react-native';
interface MonthlyPanchangData {
[date: string]: PanchangResponse;
}
export function MonthlyPanchang({ month, year, latitude, longitude }: Props) {
const [panchangData, setPanchangData] = useState<MonthlyPanchangData>({});
const [selectedDate, setSelectedDate] = useState<Date | null>(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
loadMonthData();
}, [month, year]);
async function loadMonthData() {
const daysInMonth = new Date(year, month + 1, 0).getDate();
const data: MonthlyPanchangData = {};
// Load in batches to avoid rate limits
const batchSize = 7;
for (let i = 1; i <= daysInMonth; i += batchSize) {
const batch = [];
for (let j = 0; j < batchSize && i + j <= daysInMonth; j++) {
const date = new Date(year, month, i + j);
batch.push(
getDailyPanchang(date, latitude, longitude).then((panchang) => {
data[date.toDateString()] = panchang;
})
);
}
await Promise.all(batch);
}
setPanchangData(data);
setLoading(false);
}
function getDayColor(date: Date): string {
const panchang = panchangData[date.toDateString()];
if (!panchang) return '#F3F4F6';
// Green if 3+ factors are auspicious
const auspiciousCount = [
panchang.tithi.auspicious,
panchang.nakshatra.auspicious,
panchang.yoga.auspicious,
panchang.karana.auspicious,
].filter(Boolean).length;
if (auspiciousCount >= 3) return '#D1FAE5';
if (auspiciousCount >= 2) return '#FEF3C7';
return '#FEE2E2';
}
const daysInMonth = new Date(year, month + 1, 0).getDate();
const firstDay = new Date(year, month, 1).getDay();
return (
<ScrollView style={styles.container}>
<View style={styles.calendar}>
{/* Weekday headers */}
{['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'].map((day) => (
<View key={day} style={styles.weekdayHeader}>
<Text style={styles.weekdayText}>{day}</Text>
</View>
))}
{/* Empty cells for days before month starts */}
{Array.from({ length: firstDay }).map((_, i) => (
<View key={`empty-${i}`} style={styles.dayCell} />
))}
{/* Days of month */}
{Array.from({ length: daysInMonth }).map((_, i) => {
const date = new Date(year, month, i + 1);
const panchang = panchangData[date.toDateString()];
return (
<TouchableOpacity
key={i}
style={[
styles.dayCell,
{ backgroundColor: getDayColor(date) },
selectedDate?.toDateString() === date.toDateString() && styles.selectedDay,
]}
onPress={() => setSelectedDate(date)}
>
<Text style={styles.dayNumber}>{i + 1}</Text>
{panchang && (
<>
<Text style={styles.tithiName} numberOfLines={1}>
{panchang.tithi.name}
</Text>
<Text style={styles.nakshatraName} numberOfLines={1}>
{panchang.nakshatra.name}
</Text>
</>
)}
</TouchableOpacity>
);
})}
</View>
{/* Selected date details */}
{selectedDate && panchangData[selectedDate.toDateString()] && (
<DailyPanchang
date={selectedDate}
latitude={latitude}
longitude={longitude}
/>
)}
</ScrollView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#FFF8F0',
},
calendar: {
flexDirection: 'row',
flexWrap: 'wrap',
padding: 8,
},
weekdayHeader: {
width: '14.28%',
padding: 8,
alignItems: 'center',
},
weekdayText: {
fontSize: 12,
fontWeight: 'bold',
color: '#8B4513',
},
dayCell: {
width: '14.28%',
aspectRatio: 1,
padding: 4,
borderWidth: 1,
borderColor: '#E5E7EB',
alignItems: 'center',
justifyContent: 'center',
},
selectedDay: {
borderWidth: 2,
borderColor: '#CD853F',
},
dayNumber: {
fontSize: 16,
fontWeight: 'bold',
color: '#4A4A4A',
},
tithiName: {
fontSize: 8,
color: '#6B7280',
},
nakshatraName: {
fontSize: 8,
color: '#9CA3AF',
},
});
Step 5: Push Notifications
Send daily Panchang at sunrise:
// services/panchang-notifications.ts
import * as Notifications from 'expo-notifications';
import * as Location from 'expo-location';
export class PanchangNotificationService {
async scheduleDailyNotification(userId: string) {
// Get user location
const location = await Location.getCurrentPositionAsync();
const { latitude, longitude } = location.coords;
// Get today's panchang
const panchang = await getDailyPanchang(
new Date(),
latitude,
longitude
);
// Parse sunrise time
const [hours, minutes] = panchang.sunrise.split(':').map(Number);
const sunriseDate = new Date();
sunriseDate.setHours(hours, minutes, 0);
// Schedule notification at sunrise
await Notifications.scheduleNotificationAsync({
content: {
title: '🌅 Today\'s Panchang',
body: `Tithi: ${panchang.tithi.name} | Nakshatra: ${panchang.nakshatra.name}`,
data: {
type: 'daily_panchang',
panchang,
},
},
trigger: {
hour: hours,
minute: minutes,
repeats: true,
},
});
}
async sendMuhuratAlert(activity: string, muhurat: any) {
await Notifications.scheduleNotificationAsync({
content: {
title: `✨ Auspicious Time for ${activity}`,
body: `Today is favorable for ${activity}. Check app for details.`,
data: {
type: 'muhurat_alert',
activity,
muhurat,
},
},
trigger: null, // Send immediately
});
}
async sendInauspiciousPeriodAlert(period: string, startTime: string) {
const [hours, minutes] = startTime.split(':').map(Number);
await Notifications.scheduleNotificationAsync({
content: {
title: `⚠️ ${period} Starting Soon`,
body: `Avoid important activities during ${period}: ${startTime}`,
data: {
type: 'inauspicious_period',
period,
},
},
trigger: {
hour: hours,
minute: Math.max(0, minutes - 15), // 15 mins before
repeats: true,
},
});
}
}
Step 6: Premium Features
1. Personalized Muhurat Finder
async function findPersonalizedMuhurat(
activity: string,
birthData: BirthData,
searchDays: number
): Promise<Array<{ date: Date; score: number }>> {
const birthChart = await api.getBirthChart(birthData);
const muhuratService = new MuhuratService();
const results = await muhuratService.findBestMuhurats(
activity,
new Date(),
searchDays,
birthData.latitude,
birthData.longitude
);
// Filter by personal factors (transits affecting birth chart)
return results.filter((muhurat) => {
// Check if transit planets are favorable to natal chart
return checkTransitCompatibility(muhurat.panchang, birthChart);
});
}
2. Festival Calendar Integration
interface Festival {
name: string;
date: Date;
type: 'major' | 'minor';
description: string;
rituals: string[];
}
const festivals2026: Festival[] = [
{
name: 'Makar Sankranti',
date: new Date(2026, 0, 14),
type: 'major',
description: 'Sun enters Capricorn, harvest festival',
rituals: ['Holy bath', 'Til-Gud distribution', 'Kite flying'],
},
// ... more festivals
];
function enrichPanchangWithFestival(
panchang: PanchangResponse,
date: Date
): PanchangResponse & { festival?: Festival } {
const festival = festivals2026.find(
(f) => f.date.toDateString() === date.toDateString()
);
return { ...panchang, festival };
}
3. Widget Support
// Widget configuration for home screen
export function PanchangWidget() {
const [panchang, setPanchang] = useState<PanchangResponse | null>(null);
useEffect(() => {
async function loadWidget() {
const location = await Location.getCurrentPositionAsync();
const data = await getDailyPanchang(
new Date(),
location.coords.latitude,
location.coords.longitude
);
setPanchang(data);
}
loadWidget();
}, []);
if (!panchang) return null;
return (
<View style={widgetStyles.container}>
<Text style={widgetStyles.title}>Today's Panchang</Text>
<Text style={widgetStyles.item}>🌙 {panchang.tithi.name}</Text>
<Text style={widgetStyles.item}>⭐ {panchang.nakshatra.name}</Text>
<Text style={widgetStyles.sunrise}>🌅 {panchang.sunrise}</Text>
</View>
);
}
Production Considerations
1. Location Services
async function getUserLocation(): Promise<{ latitude: number; longitude: number }> {
// Try GPS first
try {
const { status } = await Location.requestForegroundPermissionsAsync();
if (status === 'granted') {
const location = await Location.getCurrentPositionAsync();
return location.coords;
}
} catch (error) {
console.error('GPS failed:', error);
}
// Fallback to saved location or city selection
const savedLocation = await AsyncStorage.getItem('userLocation');
if (savedLocation) {
return JSON.parse(savedLocation);
}
// Default to user's city (require them to set it)
throw new Error('Location required for accurate Panchang');
}
2. Caching Strategy
// Panchang changes daily - cache for 24 hours
const cacheKey = `panchang:${year}-${month}-${day}:${latitude}:${longitude}`;
const cached = await redis.get(cacheKey);
if (cached) {
return JSON.parse(cached);
}
const panchang = await getDailyPanchang(date, latitude, longitude);
await redis.set(cacheKey, JSON.stringify(panchang), 'EX', 86400);
3. Background Refresh
// Update Panchang at midnight daily
BackgroundFetch.registerTaskAsync('update-panchang', {
minimumInterval: 86400, // 24 hours
stopOnTerminate: false,
startOnBoot: true,
});
Conclusion
You now have a production-ready daily Panchang feature powered by the RoxyAPI Vedic Astrology API. Users can view accurate Tithi, Nakshatra, Yoga, Karana calculations, get muhurat recommendations, and receive timely notifications for auspicious periods.
Key features implemented:
- Daily Panchang display with location-based calculations
- Sunrise, sunset, moonrise, moonset timings
- Auspicious and inauspicious period detection
- Muhurat selection for 6+ activities
- Monthly calendar view with color coding
- Push notifications at sunrise
- Premium personalized muhurats
- Festival calendar integration
Ready to add Panchang features to your app? Sign up for RoxyAPI and access accurate Vedic calendar calculations. Full documentation at roxyapi.com/docs.