Aligning the equinoxes to the cardinal points on a circular calendar I want to draw a calendar as a circle, with the equinoxes at the top and bottom, and the solstices at the left and right. I am prepared to accept a little inaccuracy by having exactly 365 or 366 days in the circle depending on if it is a leap year.
If I just divide the circle into 365 equal segments, then it does not line up. I can get the solstices to line up very closely, but the spring equinox always comes in 2 days late, and the autumnal equinox 2 days early.
I think this is to do with the elliptical orbit of the Earth around the Sun, and the relationship of the axes of the ellipse to the axial tilt of the Earth.
Can anyone help me with the mathematics required to adjust the angle taken up by each day in order to skew the days such that the equinoxes and solstices fit to the cardinal points of a circle?
As Mike G said, the Sun's ecliptic longitude is ideal for this application.
I see from your profile that you're a coder, with some knowledge of Python. Here's a short Python script that prints solar ecliptic longitudes for each day for any given year. (It actually prints 367 days, I figured an extra day or two may be useful). The code mostly avoids features peculiar to Python, so it should be fairly easy to translate into other languages.
My code uses the algorithm that Mike G has mentioned from Wikipedia. (I also tried another algorithm from that page, but it's not sufficiently accurate).
&quot;&quot;&quot;
 Approx Sun ecliptic longitude

 Prints daily positions for a year.
 For dates between 1950 and 2050,
 it should be accurate to within
 0.01 degrees. For details, see
 https://en.wikipedia.org/wiki/Position_of_the_Sun#Ecliptic_coordinates

 Written by PM 2Ring 2020.12.6
&quot;&quot;&quot;

from math import sin, radians
from datetime import timedelta, date

# Approximate solar ecliptic longitude
# Uses day zero = Noon UTC, 1 Jan 2000
# so we subtract half a day
def eclon_approx(n):
    n -= 0.5
    L = 280.46 + 0.9856474 * n
    g = 357.528 + 0.9856003 * n
    gr = radians(g)
    el = L + 1.915 * sin(gr) + 0.020 * sin(2 * gr)
    return el % 360

oneday = timedelta(days=1)
day_zero = date(year=2000, month=1, day=1)

@interact
def main(year=2000):
    day = date(year=year, month=1, day=1)
    d = (day - day_zero).days
    for i in range(367):
        angle = eclon_approx(d)
        print('{:03d}, &quot;{:%b-%d}&quot;, {:6.2f}'.format(i, day, angle))
        day += oneday
        d += 1


Here's the output for 2021:
000, &quot;Jan-01&quot;, 280.79
001, &quot;Jan-02&quot;, 281.80
002, &quot;Jan-03&quot;, 282.82
003, &quot;Jan-04&quot;, 283.84
004, &quot;Jan-05&quot;, 284.86
005, &quot;Jan-06&quot;, 285.88
006, &quot;Jan-07&quot;, 286.90
007, &quot;Jan-08&quot;, 287.92
008, &quot;Jan-09&quot;, 288.94
009, &quot;Jan-10&quot;, 289.96
010, &quot;Jan-11&quot;, 290.98
011, &quot;Jan-12&quot;, 292.00
012, &quot;Jan-13&quot;, 293.02
013, &quot;Jan-14&quot;, 294.03
014, &quot;Jan-15&quot;, 295.05
015, &quot;Jan-16&quot;, 296.07
016, &quot;Jan-17&quot;, 297.09
017, &quot;Jan-18&quot;, 298.11
018, &quot;Jan-19&quot;, 299.13
019, &quot;Jan-20&quot;, 300.14
020, &quot;Jan-21&quot;, 301.16
021, &quot;Jan-22&quot;, 302.18
022, &quot;Jan-23&quot;, 303.20
023, &quot;Jan-24&quot;, 304.21
024, &quot;Jan-25&quot;, 305.23
025, &quot;Jan-26&quot;, 306.25
026, &quot;Jan-27&quot;, 307.26
027, &quot;Jan-28&quot;, 308.28
028, &quot;Jan-29&quot;, 309.30
029, &quot;Jan-30&quot;, 310.31
030, &quot;Jan-31&quot;, 311.33
031, &quot;Feb-01&quot;, 312.34
032, &quot;Feb-02&quot;, 313.36
033, &quot;Feb-03&quot;, 314.37
034, &quot;Feb-04&quot;, 315.39
035, &quot;Feb-05&quot;, 316.40
036, &quot;Feb-06&quot;, 317.41
037, &quot;Feb-07&quot;, 318.43
038, &quot;Feb-08&quot;, 319.44
039, &quot;Feb-09&quot;, 320.45
040, &quot;Feb-10&quot;, 321.47
041, &quot;Feb-11&quot;, 322.48
042, &quot;Feb-12&quot;, 323.49
043, &quot;Feb-13&quot;, 324.50
044, &quot;Feb-14&quot;, 325.51
045, &quot;Feb-15&quot;, 326.52
046, &quot;Feb-16&quot;, 327.53
047, &quot;Feb-17&quot;, 328.54
048, &quot;Feb-18&quot;, 329.55
049, &quot;Feb-19&quot;, 330.56
050, &quot;Feb-20&quot;, 331.57
051, &quot;Feb-21&quot;, 332.58
052, &quot;Feb-22&quot;, 333.58
053, &quot;Feb-23&quot;, 334.59
054, &quot;Feb-24&quot;, 335.60
055, &quot;Feb-25&quot;, 336.60
056, &quot;Feb-26&quot;, 337.61
057, &quot;Feb-27&quot;, 338.61
058, &quot;Feb-28&quot;, 339.62
059, &quot;Mar-01&quot;, 340.62
060, &quot;Mar-02&quot;, 341.63
061, &quot;Mar-03&quot;, 342.63
062, &quot;Mar-04&quot;, 343.63
063, &quot;Mar-05&quot;, 344.63
064, &quot;Mar-06&quot;, 345.64
065, &quot;Mar-07&quot;, 346.64
066, &quot;Mar-08&quot;, 347.64
067, &quot;Mar-09&quot;, 348.64
068, &quot;Mar-10&quot;, 349.64
069, &quot;Mar-11&quot;, 350.64
070, &quot;Mar-12&quot;, 351.64
071, &quot;Mar-13&quot;, 352.63
072, &quot;Mar-14&quot;, 353.63
073, &quot;Mar-15&quot;, 354.63
074, &quot;Mar-16&quot;, 355.62
075, &quot;Mar-17&quot;, 356.62
076, &quot;Mar-18&quot;, 357.62
077, &quot;Mar-19&quot;, 358.61
078, &quot;Mar-20&quot;, 359.60
079, &quot;Mar-21&quot;,   0.60
080, &quot;Mar-22&quot;,   1.59
081, &quot;Mar-23&quot;,   2.58
082, &quot;Mar-24&quot;,   3.58
083, &quot;Mar-25&quot;,   4.57
084, &quot;Mar-26&quot;,   5.56
085, &quot;Mar-27&quot;,   6.55
086, &quot;Mar-28&quot;,   7.54
087, &quot;Mar-29&quot;,   8.53
088, &quot;Mar-30&quot;,   9.51
089, &quot;Mar-31&quot;,  10.50
090, &quot;Apr-01&quot;,  11.49
091, &quot;Apr-02&quot;,  12.48
092, &quot;Apr-03&quot;,  13.46
093, &quot;Apr-04&quot;,  14.45
094, &quot;Apr-05&quot;,  15.43
095, &quot;Apr-06&quot;,  16.42
096, &quot;Apr-07&quot;,  17.40
097, &quot;Apr-08&quot;,  18.39
098, &quot;Apr-09&quot;,  19.37
099, &quot;Apr-10&quot;,  20.35
100, &quot;Apr-11&quot;,  21.33
101, &quot;Apr-12&quot;,  22.31
102, &quot;Apr-13&quot;,  23.29
103, &quot;Apr-14&quot;,  24.27
104, &quot;Apr-15&quot;,  25.25
105, &quot;Apr-16&quot;,  26.23
106, &quot;Apr-17&quot;,  27.21
107, &quot;Apr-18&quot;,  28.19
108, &quot;Apr-19&quot;,  29.17
109, &quot;Apr-20&quot;,  30.14
110, &quot;Apr-21&quot;,  31.12
111, &quot;Apr-22&quot;,  32.10
112, &quot;Apr-23&quot;,  33.07
113, &quot;Apr-24&quot;,  34.05
114, &quot;Apr-25&quot;,  35.02
115, &quot;Apr-26&quot;,  35.99
116, &quot;Apr-27&quot;,  36.97
117, &quot;Apr-28&quot;,  37.94
118, &quot;Apr-29&quot;,  38.91
119, &quot;Apr-30&quot;,  39.88
120, &quot;May-01&quot;,  40.85
121, &quot;May-02&quot;,  41.82
122, &quot;May-03&quot;,  42.79
123, &quot;May-04&quot;,  43.76
124, &quot;May-05&quot;,  44.73
125, &quot;May-06&quot;,  45.70
126, &quot;May-07&quot;,  46.67
127, &quot;May-08&quot;,  47.64
128, &quot;May-09&quot;,  48.61
129, &quot;May-10&quot;,  49.57
130, &quot;May-11&quot;,  50.54
131, &quot;May-12&quot;,  51.50
132, &quot;May-13&quot;,  52.47
133, &quot;May-14&quot;,  53.44
134, &quot;May-15&quot;,  54.40
135, &quot;May-16&quot;,  55.36
136, &quot;May-17&quot;,  56.33
137, &quot;May-18&quot;,  57.29
138, &quot;May-19&quot;,  58.25
139, &quot;May-20&quot;,  59.22
140, &quot;May-21&quot;,  60.18
141, &quot;May-22&quot;,  61.14
142, &quot;May-23&quot;,  62.10
143, &quot;May-24&quot;,  63.06
144, &quot;May-25&quot;,  64.03
145, &quot;May-26&quot;,  64.99
146, &quot;May-27&quot;,  65.95
147, &quot;May-28&quot;,  66.91
148, &quot;May-29&quot;,  67.87
149, &quot;May-30&quot;,  68.82
150, &quot;May-31&quot;,  69.78
151, &quot;Jun-01&quot;,  70.74
152, &quot;Jun-02&quot;,  71.70
153, &quot;Jun-03&quot;,  72.66
154, &quot;Jun-04&quot;,  73.62
155, &quot;Jun-05&quot;,  74.57
156, &quot;Jun-06&quot;,  75.53
157, &quot;Jun-07&quot;,  76.49
158, &quot;Jun-08&quot;,  77.45
159, &quot;Jun-09&quot;,  78.40
160, &quot;Jun-10&quot;,  79.36
161, &quot;Jun-11&quot;,  80.31
162, &quot;Jun-12&quot;,  81.27
163, &quot;Jun-13&quot;,  82.23
164, &quot;Jun-14&quot;,  83.18
165, &quot;Jun-15&quot;,  84.14
166, &quot;Jun-16&quot;,  85.09
167, &quot;Jun-17&quot;,  86.05
168, &quot;Jun-18&quot;,  87.00
169, &quot;Jun-19&quot;,  87.96
170, &quot;Jun-20&quot;,  88.91
171, &quot;Jun-21&quot;,  89.86
172, &quot;Jun-22&quot;,  90.82
173, &quot;Jun-23&quot;,  91.77
174, &quot;Jun-24&quot;,  92.73
175, &quot;Jun-25&quot;,  93.68
176, &quot;Jun-26&quot;,  94.63
177, &quot;Jun-27&quot;,  95.59
178, &quot;Jun-28&quot;,  96.54
179, &quot;Jun-29&quot;,  97.50
180, &quot;Jun-30&quot;,  98.45
181, &quot;Jul-01&quot;,  99.40
182, &quot;Jul-02&quot;, 100.36
183, &quot;Jul-03&quot;, 101.31
184, &quot;Jul-04&quot;, 102.26
185, &quot;Jul-05&quot;, 103.22
186, &quot;Jul-06&quot;, 104.17
187, &quot;Jul-07&quot;, 105.12
188, &quot;Jul-08&quot;, 106.08
189, &quot;Jul-09&quot;, 107.03
190, &quot;Jul-10&quot;, 107.98
191, &quot;Jul-11&quot;, 108.94
192, &quot;Jul-12&quot;, 109.89
193, &quot;Jul-13&quot;, 110.84
194, &quot;Jul-14&quot;, 111.80
195, &quot;Jul-15&quot;, 112.75
196, &quot;Jul-16&quot;, 113.71
197, &quot;Jul-17&quot;, 114.66
198, &quot;Jul-18&quot;, 115.61
199, &quot;Jul-19&quot;, 116.57
200, &quot;Jul-20&quot;, 117.52
201, &quot;Jul-21&quot;, 118.48
202, &quot;Jul-22&quot;, 119.43
203, &quot;Jul-23&quot;, 120.39
204, &quot;Jul-24&quot;, 121.34
205, &quot;Jul-25&quot;, 122.30
206, &quot;Jul-26&quot;, 123.25
207, &quot;Jul-27&quot;, 124.21
208, &quot;Jul-28&quot;, 125.16
209, &quot;Jul-29&quot;, 126.12
210, &quot;Jul-30&quot;, 127.07
211, &quot;Jul-31&quot;, 128.03
212, &quot;Aug-01&quot;, 128.99
213, &quot;Aug-02&quot;, 129.94
214, &quot;Aug-03&quot;, 130.90
215, &quot;Aug-04&quot;, 131.86
216, &quot;Aug-05&quot;, 132.81
217, &quot;Aug-06&quot;, 133.77
218, &quot;Aug-07&quot;, 134.73
219, &quot;Aug-08&quot;, 135.69
220, &quot;Aug-09&quot;, 136.65
221, &quot;Aug-10&quot;, 137.61
222, &quot;Aug-11&quot;, 138.57
223, &quot;Aug-12&quot;, 139.52
224, &quot;Aug-13&quot;, 140.48
225, &quot;Aug-14&quot;, 141.44
226, &quot;Aug-15&quot;, 142.41
227, &quot;Aug-16&quot;, 143.37
228, &quot;Aug-17&quot;, 144.33
229, &quot;Aug-18&quot;, 145.29
230, &quot;Aug-19&quot;, 146.25
231, &quot;Aug-20&quot;, 147.21
232, &quot;Aug-21&quot;, 148.18
233, &quot;Aug-22&quot;, 149.14
234, &quot;Aug-23&quot;, 150.10
235, &quot;Aug-24&quot;, 151.07
236, &quot;Aug-25&quot;, 152.03
237, &quot;Aug-26&quot;, 152.99
238, &quot;Aug-27&quot;, 153.96
239, &quot;Aug-28&quot;, 154.93
240, &quot;Aug-29&quot;, 155.89
241, &quot;Aug-30&quot;, 156.86
242, &quot;Aug-31&quot;, 157.82
243, &quot;Sep-01&quot;, 158.79
244, &quot;Sep-02&quot;, 159.76
245, &quot;Sep-03&quot;, 160.73
246, &quot;Sep-04&quot;, 161.70
247, &quot;Sep-05&quot;, 162.67
248, &quot;Sep-06&quot;, 163.63
249, &quot;Sep-07&quot;, 164.60
250, &quot;Sep-08&quot;, 165.58
251, &quot;Sep-09&quot;, 166.55
252, &quot;Sep-10&quot;, 167.52
253, &quot;Sep-11&quot;, 168.49
254, &quot;Sep-12&quot;, 169.46
255, &quot;Sep-13&quot;, 170.44
256, &quot;Sep-14&quot;, 171.41
257, &quot;Sep-15&quot;, 172.38
258, &quot;Sep-16&quot;, 173.36
259, &quot;Sep-17&quot;, 174.33
260, &quot;Sep-18&quot;, 175.31
261, &quot;Sep-19&quot;, 176.28
262, &quot;Sep-20&quot;, 177.26
263, &quot;Sep-21&quot;, 178.24
264, &quot;Sep-22&quot;, 179.22
265, &quot;Sep-23&quot;, 180.19
266, &quot;Sep-24&quot;, 181.17
267, &quot;Sep-25&quot;, 182.15
268, &quot;Sep-26&quot;, 183.13
269, &quot;Sep-27&quot;, 184.11
270, &quot;Sep-28&quot;, 185.09
271, &quot;Sep-29&quot;, 186.08
272, &quot;Sep-30&quot;, 187.06
273, &quot;Oct-01&quot;, 188.04
274, &quot;Oct-02&quot;, 189.02
275, &quot;Oct-03&quot;, 190.01
276, &quot;Oct-04&quot;, 190.99
277, &quot;Oct-05&quot;, 191.98
278, &quot;Oct-06&quot;, 192.96
279, &quot;Oct-07&quot;, 193.95
280, &quot;Oct-08&quot;, 194.94
281, &quot;Oct-09&quot;, 195.92
282, &quot;Oct-10&quot;, 196.91
283, &quot;Oct-11&quot;, 197.90
284, &quot;Oct-12&quot;, 198.89
285, &quot;Oct-13&quot;, 199.88
286, &quot;Oct-14&quot;, 200.87
287, &quot;Oct-15&quot;, 201.86
288, &quot;Oct-16&quot;, 202.85
289, &quot;Oct-17&quot;, 203.84
290, &quot;Oct-18&quot;, 204.83
291, &quot;Oct-19&quot;, 205.83
292, &quot;Oct-20&quot;, 206.82
293, &quot;Oct-21&quot;, 207.81
294, &quot;Oct-22&quot;, 208.81
295, &quot;Oct-23&quot;, 209.80
296, &quot;Oct-24&quot;, 210.80
297, &quot;Oct-25&quot;, 211.80
298, &quot;Oct-26&quot;, 212.79
299, &quot;Oct-27&quot;, 213.79
300, &quot;Oct-28&quot;, 214.79
301, &quot;Oct-29&quot;, 215.79
302, &quot;Oct-30&quot;, 216.79
303, &quot;Oct-31&quot;, 217.79
304, &quot;Nov-01&quot;, 218.79
305, &quot;Nov-02&quot;, 219.79
306, &quot;Nov-03&quot;, 220.79
307, &quot;Nov-04&quot;, 221.79
308, &quot;Nov-05&quot;, 222.79
309, &quot;Nov-06&quot;, 223.79
310, &quot;Nov-07&quot;, 224.80
311, &quot;Nov-08&quot;, 225.80
312, &quot;Nov-09&quot;, 226.80
313, &quot;Nov-10&quot;, 227.81
314, &quot;Nov-11&quot;, 228.81
315, &quot;Nov-12&quot;, 229.82
316, &quot;Nov-13&quot;, 230.83
317, &quot;Nov-14&quot;, 231.83
318, &quot;Nov-15&quot;, 232.84
319, &quot;Nov-16&quot;, 233.85
320, &quot;Nov-17&quot;, 234.85
321, &quot;Nov-18&quot;, 235.86
322, &quot;Nov-19&quot;, 236.87
323, &quot;Nov-20&quot;, 237.88
324, &quot;Nov-21&quot;, 238.89
325, &quot;Nov-22&quot;, 239.90
326, &quot;Nov-23&quot;, 240.91
327, &quot;Nov-24&quot;, 241.92
328, &quot;Nov-25&quot;, 242.93
329, &quot;Nov-26&quot;, 243.94
330, &quot;Nov-27&quot;, 244.96
331, &quot;Nov-28&quot;, 245.97
332, &quot;Nov-29&quot;, 246.98
333, &quot;Nov-30&quot;, 247.99
334, &quot;Dec-01&quot;, 249.01
335, &quot;Dec-02&quot;, 250.02
336, &quot;Dec-03&quot;, 251.03
337, &quot;Dec-04&quot;, 252.05
338, &quot;Dec-05&quot;, 253.06
339, &quot;Dec-06&quot;, 254.08
340, &quot;Dec-07&quot;, 255.09
341, &quot;Dec-08&quot;, 256.11
342, &quot;Dec-09&quot;, 257.12
343, &quot;Dec-10&quot;, 258.14
344, &quot;Dec-11&quot;, 259.16
345, &quot;Dec-12&quot;, 260.17
346, &quot;Dec-13&quot;, 261.19
347, &quot;Dec-14&quot;, 262.21
348, &quot;Dec-15&quot;, 263.22
349, &quot;Dec-16&quot;, 264.24
350, &quot;Dec-17&quot;, 265.26
351, &quot;Dec-18&quot;, 266.28
352, &quot;Dec-19&quot;, 267.29
353, &quot;Dec-20&quot;, 268.31
354, &quot;Dec-21&quot;, 269.33
355, &quot;Dec-22&quot;, 270.35
356, &quot;Dec-23&quot;, 271.37
357, &quot;Dec-24&quot;, 272.39
358, &quot;Dec-25&quot;, 273.40
359, &quot;Dec-26&quot;, 274.42
360, &quot;Dec-27&quot;, 275.44
361, &quot;Dec-28&quot;, 276.46
362, &quot;Dec-29&quot;, 277.48
363, &quot;Dec-30&quot;, 278.50
364, &quot;Dec-31&quot;, 279.52
365, &quot;Jan-01&quot;, 280.54
366, &quot;Jan-02&quot;, 281.56

That @interact decorator before the main function isn't standard Python, it's a feature of Sage. You can play with an interactive version of this script on a SageMath server here.