[Question]
  [
# Background
Some holidays have fixed, easy-to-remember dates, like Oct 31, Dec 25, etc. Some, however, want to be troublesome. They're specified as things like "the first Monday in September" or "the fourth Thursday in November". How am I supposed to know when that is?
All I know is that Thanksgiving is fast approaching, so I need a program to help me figure out when it is. Some people even say that it's *tomorrow*, so your program needs to be as short as possible to make sure I can re-type it in time.
# The Challenge
Create a program or function that, given an up-to-four-digit year (e.g. 2015 or 1984), outputs or returns the date of the United States' Thanksgiving in that year. Thanksgiving is defined as the fourth Thursday of November according to [the Wikipedia page](https://en.wikipedia.org/wiki/Thanksgiving). *(Hint: that page also includes some interesting information on the date pattern.)*
**Input**: a decimal number with a maximum of four digits representing a year in the Common Era (C.E.). Examples: 987, 1984, 2101
**Output**: the date, including month and day, on which Thanksgiving falls, or would fall if it existed, in that year. This may be in any reasonable format; use your best judgment. Use the Gregorian Calendar in all cases, even if it was not in use at the time.
*(Note: Make sure to handle leap years correctly!)*
**Test cases**
Input 1:
```
2015
```
Output 1:
```
Nov 26
```
Input 2:
```
1917
```
Output 2:
```
Nov 22
```
# Scoring
Submissions will be scored in **bytes**. I recommend [this website](http://bytesizematters.com) to keep track of your byte count, though you can use any counter you like.
### Bonuses
**-25%** to your score if you handle B.C.E. dates as negative numbers (e.g. -480 would be the year of the battle of Thermopylae).
Negative test case input:
```
-480
```
Corresponding output:
```
Nov 25
```
This is [code-golf](/questions/tagged/code-golf "show questions tagged 'code-golf'"), so the lowest score wins!
Edit: I am marking Thomas Kwa's TI-BASIC submission as accepted. Don't let this discourage you from submitting new entries!
## Leaderboards
Here is a Stack Snippet to generate both a regular leaderboard and an overview of winners by language.
To make sure that your answer shows up, please start your answer with a headline, using the following Markdown template:
```
# Language Name, N bytes
```
where `N` is the size of your submission. If you improve your score, you *can* keep old scores in the headline, by striking them through. For instance:
```
# Ruby, <s>104</s> <s>101</s> 96 bytes
```
If there you want to include multiple numbers in your header (e.g. because your score is the sum of two files or you want to list interpreter flag penalties separately), make sure that the actual score is the *last* number in the header:
```
# Perl, 43 + 2 (-p flag) = 45 bytes
```
You can also make the language name a link which will then show up in the leaderboard snippet:
```
# [><>](http://esolangs.org/wiki/Fish), 121 bytes
```
```
var QUESTION_ID=64785,OVERRIDE_USER=45162;function answersUrl(e){return"http://api.stackexchange.com/2.2/questions/"+QUESTION_ID+"/answers?page="+e+"&pagesize=100&order=desc&sort=creation&site=codegolf&filter="+ANSWER_FILTER}function commentUrl(e,s){return"http://api.stackexchange.com/2.2/answers/"+s.join(";")+"/comments?page="+e+"&pagesize=100&order=desc&sort=creation&site=codegolf&filter="+COMMENT_FILTER}function getAnswers(){jQuery.ajax({url:answersUrl(answer_page++),method:"get",dataType:"jsonp",crossDomain:!0,success:function(e){answers.push.apply(answers,e.items),answers_hash=[],answer_ids=[],e.items.forEach(function(e){e.comments=[];var s=+e.share_link.match(/\d+/);answer_ids.push(s),answers_hash[s]=e}),e.has_more||(more_answers=!1),comment_page=1,getComments()}})}function getComments(){jQuery.ajax({url:commentUrl(comment_page++,answer_ids),method:"get",dataType:"jsonp",crossDomain:!0,success:function(e){e.items.forEach(function(e){e.owner.user_id===OVERRIDE_USER&&answers_hash[e.post_id].comments.push(e)}),e.has_more?getComments():more_answers?getAnswers():process()}})}function getAuthorName(e){return e.owner.display_name}function process(){var e=[];answers.forEach(function(s){var r=s.body;s.comments.forEach(function(e){OVERRIDE_REG.test(e.body)&&(r="<h1>"+e.body.replace(OVERRIDE_REG,"")+"</h1>")});var a=r.match(SCORE_REG);a&&e.push({user:getAuthorName(s),size:+a[2],language:a[1],link:s.share_link})}),e.sort(function(e,s){var r=e.size,a=s.size;return r-a});var s={},r=1,a=null,n=1;e.forEach(function(e){e.size!=a&&(n=r),a=e.size,++r;var t=jQuery("#answer-template").html();t=t.replace("{{PLACE}}",n+".").replace("{{NAME}}",e.user).replace("{{LANGUAGE}}",e.language).replace("{{SIZE}}",e.size).replace("{{LINK}}",e.link),t=jQuery(t),jQuery("#answers").append(t);var o=e.language;/<a/.test(o)&&(o=jQuery(o).text()),s[o]=s[o]||{lang:e.language,user:e.user,size:e.size,link:e.link}});var t=[];for(var o in s)s.hasOwnProperty(o)&&t.push(s[o]);t.sort(function(e,s){return e.lang>s.lang?1:e.lang<s.lang?-1:0});for(var c=0;c<t.length;++c){var i=jQuery("#language-template").html(),o=t[c];i=i.replace("{{LANGUAGE}}",o.lang).replace("{{NAME}}",o.user).replace("{{SIZE}}",o.size).replace("{{LINK}}",o.link),i=jQuery(i),jQuery("#languages").append(i)}}var ANSWER_FILTER="!t)IWYnsLAZle2tQ3KqrVveCRJfxcRLe",COMMENT_FILTER="!)Q2B_A2kjfAiU78X(md6BoYk",answers=[],answers_hash,answer_ids,answer_page=1,more_answers=!0,comment_page;getAnswers();var SCORE_REG=/<h\d>\s*([^\n,]*[^\s,]),.*?([\d.]+)(?=[^\n\d<>]*(?:<(?:s>[^\n<>]*<\/s>|[^\n<>]+>)[^\n\d<>]*)*<\/h\d>)/,OVERRIDE_REG=/^Override\s*header:\s*/i;
```
```
body{text-align:left!important}#answer-list,#language-list{padding:10px;width:290px;float:left}table thead{font-weight:700}table td{padding:5px}
```
```
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <link rel="stylesheet" type="text/css" href="//cdn.sstatic.net/codegolf/all.css?v=83c949450c8b"> <div id="answer-list"> <h2>Leaderboard</h2> <table class="answer-list"> <thead> <tr><td></td><td>Author</td><td>Language</td><td>Size</td></tr></thead> <tbody id="answers"> </tbody> </table> </div><div id="language-list"> <h2>Winners by Language</h2> <table class="language-list"> <thead> <tr><td>Language</td><td>User</td><td>Score</td></tr></thead> <tbody id="languages"> </tbody> </table> </div><table style="display: none"> <tbody id="answer-template"> <tr><td>{{PLACE}}</td><td>{{NAME}}</td><td>{{LANGUAGE}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr></tbody> </table> <table style="display: none"> <tbody id="language-template"> <tr><td>{{LANGUAGE}}</td><td>{{NAME}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr></tbody> </table>
```
  
[Answer]
# TI-BASIC, 15 bytes \* 0.75 = 11.25
*Tested on my TI-84+ calculator*
```
1129-dayOfWk(Ans+ᴇ4,9,1
```
Thankgiving is November 29, minus the day of the week of September 1st, where 1 is Sunday and 7 is Saturday. This outputs in the format `MMDD`.
Test cases: `2015` -> `1126`, `1917` -> `1122`, `-480` -> `1125` have been verified. TI-BASIC seems to use the Gregorian calendar for all dates.
TI-BASIC doesn't support negative years, but this gets the bonus because we add 10000 to the input. Because the Gregorian calendar has a period of 400 years, this doesn't change the day of the week.
[Answer]
## PHP, ~~65~~ ~~48~~ ~~42~~ ~~41~~ 36 (+2 for `-F`) = 38 bytes
```
<?date(Md,strtotime("4thuXI$argn"));
```
Takes input as the first command line argument. Runs with warnings, which are acceptable by our rules. Prints `NovDD`, where `DD` is the day of Thanksgiving.
No online link because ideone doesn't support command line args and I don't know of an online interpreter that does.
Thanks to Alexander O'Mara for teaching me a new trick, and primo for a significant reduction
[Answer]
## Mathematica, ~~59~~ 38 bytes
```
DayRange[{#,11},{#,12},Thursday][[4]]&
```
[Answer]
# JavaScript (ES6), ~~42~~ ~~40~~ 31 bytes - 25% = 23.25
```
a=>28.11-new Date(a,8).getDay()
```
Since the date "may be in any reasonable format", this function uses `DD.MM`. I wrote a [TeaScript answer](https://codegolf.stackexchange.com/a/64805/45393) with a different technique, but this formula was shorter.
## Explanation
As the months are zero based, `new Date(a,10)` returns a `Date` object representing November 1 of the specified year.
Since `getDay()` returns a number representing the day of week from `0..6` we want to map from
```
Su Mo Tu We Th Fr Sa 
0  1  2  3  4  5  6  
to to to to to to to
4  3  2  1  0  6  5  
```
then add 22. It turns out that `(11 - new Date(a,10).getDay()) % 7` will do the trick. As [@Thomas Kwa](https://codegolf.stackexchange.com/users/39328/thomas-kwa) pointed out, this is the same as `28-new Date(a,8).getDay()` which is 28 minus the day of the week of September 1.
[Answer]
# [Japt](https://github.com/ETHproductions/Japt), ~~43~~ ~~37~~ ~~36~~ ~~35~~ 29 bytes - 25% = 21.75
**Japt** is a shortened version of **Ja**vaScri**pt**.
```
`{28.11-?w D?e(U,8).getDay()}
```
Hahaha, I found a *really* cheaty trick: the interpreter ignores any brackets inside strings (used to insert code) while decompressing them, so we can compress the entire source code to save a byte >:D
The two `?`s should be the Unicode unprintables U+0098 and U+0085, respectively. [Try it online!](http://ethproductions.github.io/japt?v=9b914b60365b0031f09d30c79d98d504131f1328&code=YHsyOC4xMS2adyBEhWUoVSw4KS5nZXREYXkoKX0=&input=MjAxNQ==)
After decompression, the code evaluates to this:
```
"{28.11-new Date(U,8).getDay()}"
```
Which evaluates to:
```
""+(28.11-new Date(U,8).getDay())+""
```
Which gives the proper output.
Uses [intrepidcoder's technique](https://codegolf.stackexchange.com/a/64797/42545), outputting in format `dd.mm`. Properly supports negative years.
Suggestions welcome!
**Edit:** As of Dec 2, you can now use this **11-byte** code (scoring **8.25 points**):
```
28.11-ÐU8 e
```
(I so wish I had implemented this sooner!)
[Answer]
# [Vitsy](https://github.com/VTCAKAVSMoACE/Vitsy), 44 bytes
I'm calculating with *pure mathemagics*!
Golfed:
```
Ve2*V2-V41m+Vaa*Dv1m-Vv4*1m+7M-baa*/+N
/D1M-
```
Ungolfed (moved the method call to the first line to make it readable):
```
Ve2*V2-V4/D1M-+Vaa*Dv/D1M--Vv4*/D1M-+7M-baa*/+N
V         Save the input as a final variable.
 e2*      Push 28 to the stack.
    V         Push the input to the stack.
     2-         Subtract two.
       V4/D1M-        Get floor(input/4).
              +        Add it to the total.
               Vaa*Dv/D1M-          Get floor(input/100), and save 100 as a temp
                                    variable in the process.
                          -          Subtract it from the total.
                           Vv4*/D1M-         Get floor(input/400).
                                    +         Add it to the total.
                                     7M       Modulo by seven.
                                       -       Subtract the result from 28.
                                        baa*/+      Add .11
                                              N      Output as number.
```
There's probably a better algorithm for this (and this is likely horridly golfed), but for those wondering, my algorithm comes from [here](https://en.wikipedia.org/wiki/Determination_of_the_day_of_the_week).
[Try it online!](http://vitsy.tryitonline.net/#code=VmUyKlYyLVY0MW0rVmFhKkR2MW0tVnY0KjFtKzdNLWJhYSovK04KL0QxTS0&input=&args=MjAxNg&debug=on)
~~Do I get bonus points for calculating it and having exactly 42 bytes?~~ Dreams ruined.
Thanks to @Hosch250 for pointing out I was doing it wrong. :D Fixed.
[Answer]
# Python, 38 \* 0.75 = 28.5 bytes
```
lambda x:28.11-(x-2+x/4-x/100+x/400)%7
```
This works with negative years in the manner specified in the question, although it's come to my attention that there is no year 0 in the Gregorian calendar so this behavior is a bit suspect.
[Answer]
# JavaScript (ES6), 43.5
Actual byte count is 58. The bonus of -25% applies => 58 \* 0.75 = **43.5**
```
s=>new Date(s,10,(a=new Date(s,10).getDay())<5?26-a:a+21)
```
Pretty straight ~~and silly~~ way as it could be, without any tricky workarounds or calculations.
De-golf (ES5) + demo:
```
function t(s) {
    a = new Date(s, 10).getDay();
    alert(new Date(s,10,a<=4?26-a:a+21))
}
t(prompt())
```
Note, that entering year 0-100 produces 1900-2000 year. Though, it looks like 0-100 years give the same date as do 1900-2000, judging from the other answers.
---
Replacing `a+18` with `22`, because it's called only in "else", and "else" occurs only if a is neither greater nor less than 4, i.e. exactly 4.
---
Replacing `a<4?26-a:a>4?a+21:22` with `a<=4?26-a:a+21`
[Answer]
# TeaScript, ~~35~~ ~~33~~ 24 bytes - 25% = 18
```
28.11-new D(x,8).getDay¡
```
This is the same method as [my JavaScript answer](https://codegolf.stackexchange.com/a/64797/45393), which uses [Thomas Kwa's](https://codegolf.stackexchange.com/a/64890/45393) clever formula.
### Alternate Version with Explanation
```
r(22,28)F(#/h/t(new D(x,10,l)))+'-11'
r(22,28)    // Range from 22 to 28
        F(    // filter, keeps elements for which the function returns true. 
          #    // Expands to function(l,i,a,b)
           /h/    // RegExp literal, Thursday is the only day with an 'h'.
              t(    // test, true if date string contains an 'h'.
                new D(x,10,l) // Create date object
                             ))+'-11' // Append '-11' for the month.
```
[Answer]
# Jython, 141 155 Bytes
Uses the Java Calendar and Scanner classes with Python syntax.
```
import java.util.Scanner as s;import java.util.Calendar as c
d=c.getInstance();k=s(System.in);d.set(c.YEAR,k.nextInt());d.set(c.DAY_OF_WEEK,c.THURSDAY)
```
**Edit:** Minor syntax issues, added 14 bytes.
Also see my [Brainfuck](https://codegolf.stackexchange.com/a/64806/47629) version.
[Answer]
## Python, ~~83~~ ~~81~~ 78 bytes
```
from datetime import*
lambda a:'Nov '+`((10-datetime(a,11,1).weekday())%7)+22`
```
* **-2 bytes:** added a name to import (thanks @Κριτικσι Λίθος)
* **-1 bytes:** changed to \*import\*\* (thanks @FryAmTheEggman)
* **-2 bytes:** changed to repr to convert the day (thanks @willem)
[Answer]
## Excel, ~~367~~ ~~154~~ 53 - 25% = 39.75 bytes
Assumes the year is held in cell A1, in Date format. Returns the integer number of the day in November on which Thanksgiving is held. 
This only accounts for normal leap years. It does not account for the fact that the years, 2100, 2200, 2300 are not leap years. 
This is only designed to work for 1621 onwards - i.e. since Thanksgiving began being held. (Although it will certainly work all the way back to 0 A.D.).
```
=IF(MOD(YEAR(A1),4)=0,IF(WEEKDAY(305+DATEVALUE(("01/01/"&TEXT(A1,"yyyy"))))<6,1127-WEEKDAY(305+DATEVALUE(("01/01/"&TEXT(A1,"yyyy")))),1134-WEEKDAY(305+DATEVALUE(("01/01/"&TEXT(A1,"yyyy"))))),IF(WEEKDAY(304+DATEVALUE(("01/01/"&TEXT(A1,"yyyy"))))<6,1127-WEEKDAY(304+DATEVALUE(("01/01/"&TEXT(A1,"yyyy")))),1134-WEEKDAY(304+DATEVALUE(("01/01/"&TEXT(A1,"yyyy"))))))
```
Pretty-printed:
```
=IF(MOD(YEAR(A1),4)=0,
    IF(WEEKDAY(305+DATEVALUE(("01/01/"&TEXT(A1,"yyyy"))))<6,
       1127-WEEKDAY(305+DATEVALUE(("01/01/"&TEXT(A1,"yyyy")))),
       1134-WEEKDAY(305+DATEVALUE(("01/01/"&TEXT(A1,"yyyy"))))),
    IF(WEEKDAY(304+DATEVALUE(("01/01/"&TEXT(A1,"yyyy"))))<6,
       1127-WEEKDAY(304+DATEVALUE(("01/01/"&TEXT(A1,"yyyy")))),
       1134-WEEKDAY(304+DATEVALUE(("01/01/"&TEXT(A1,"yyyy"))))))
```
Gah! Instead of calculating based on the 1st of Jan, then doing lots of leap year calculations to cope with the 29th of Feb, I should have based the calculations on the 1st of Nov. n.b. This now deals correctly with the years 2100, 2200 and 2300, but makes the implementation dependent on your Excel installation's default date format. This version is designed for dd/mm/yyyy:
```
 =IF(WEEKDAY(DATEVALUE(("01/11/"&TEXT(C1,"yyyy"))))<6,  
     1127-WEEKDAY(DATEVALUE(("01/11/"&TEXT(C1,"yyyy")))),
     1134-WEEKDAY(DATEVALUE(("01/11/"&TEXT(C1,"yyyy")))))
```
And now that I've done the pfaffing about to get a terse calculation in Smalltalk, backporting it to Excel results in:
```
=DATE(A1,11,MOD(12-WEEKDAY(DATE(9600+A1,11,1)),7)+22)
```
(with the year still in A1, but as an integer). This works even for years 2100, 2200 and 2300, for all dates from 7700BC/E onwards, using Thomas Kwa's date repetition trick.
[Answer]
## PowerShell, ~~67~~ ~~64~~ ~~84~~ ~~72~~ ~~58~~ 45 Bytes
```
param($a)'Nov';28-(date "00$a/9/1").DayOfWeek
```
We take our input integer as `$a`, and immediately output `Nov` and a newline. Then we take `$a` and prepend it with zeroes and September 1st with `00$a/9/1` before generating a new `date` and determining what `DayOfWeek` that is. If September 1st is on a Sunday (`.DayOfWeek` equal to `0`), Thanksgiving is on the 28th. If September 1st is on a Monday (`.DayOfWeek` equal to `1`), Thanksgiving is on the 27th. And so on. Thus, we subtract that day of the week from `28` to output our answer.
Prepending with double-zeroes accounts for single- and double-digit years without interrupting parsing for three- or four-digit years. Doesn't work for negative numbers, as .NET `datetime` doesn't support years less than `0`.
Thanks to [TessellatingHeckler](https://codegolf.stackexchange.com/users/571/tessellatingheckler) and [Toby Speight](https://codegolf.stackexchange.com/users/39490/toby-speight) for assistance on this.
[Answer]
# Golfscript, 25 \* 0.75 = 18.75 bytes
```
~.4/.25/.4/2---+7%28\--11
```
This uses Sakamoto's formula for the day of the week. Since there are people doing this, the output is in the form of `dd-mm`. My previous submission can be found below:
```
~.4/.25/.4/2---+7%"Nov "28@-
```
[Answer]
# TSQL, ~~478~~ 296 bytes
Just for funsies. Typically, you'd have a date dimensional table to make this a simple `select * from dimDate where [Year] = @Year and [Holiday] = 'Thanksgiving'` but in the absence of that...
```
create function a(@y varchar(4))returns date as begin declare @d date,@i int=0 set @d=convert(date,@y+'-11-01')declare @t table(d date,c int identity)while @i<28 begin if datepart(weekday,@d)=5 insert @t(d) select @d select @d=dateadd(d,1,@d),@i+=1 end select @d=d from @t where c=4 return @d end
```
Ungolfed:
```
if exists(select * from sys.objects where name='a' and [type]='FN') drop function a
go
create function a(@y varchar(4))returns date
-- select dbo.a('2015')
as
begin
    declare @d date,@i int=0;
    set @d=convert(date,@y+'-11-01'); -- cannot golf out dashes for dates <year 1000
    declare @t table(d date,c int identity)
    while @i<28 
    begin -- populate "November" array
        if datepart(weekday,@d)=5 insert @t(d) select @d -- assumes @@datefirst = 7
        select @d=dateadd(d,1,@d),@i+=1
    end;
    select @d=d from @t where c=4 
    return @d
end
```
[Answer]
# Pyth, ~~30~~ 28 \* 75% = 21 bytes
I'm 100% positive that this could be made shorter, but hey, it's my first Pyth program! \o/
```
-28.11%+-+-Q2/Q4/Q100/Q400 7
```
[Test suite](https://pyth.herokuapp.com/?code=-28.11%25%2B-%2B-Q2%2FQ4%2FQ100%2FQ400+7&input=2015&test_suite=1&test_suite_input=2014%0A2015%0A2016%0A2017%0A1917%0A-480%0A0&debug=0)
Outputs the date in `dd.mm` format.
*Please* suggest ways to golf this if you can! I'd like to learn more about Pyth.
[Answer]
# Excel, ~~64~~ 48
Year in A1
~~=DATE(A1,11,CHOOSE(WEEKDAY(DATE(A1,11,1)),26,25,24,23,22,28,27))~~
```
=DATE(A1,11,MOD(12-WEEKDAY(DATE(A1,11,1)),7)+22)
```
[Answer]
## Befunge, 41 Bytes
```
47*&:::4"d"*/\"d"/-\4/++5+7%-" voN",,,,.@
```
Run on [this interpreter](http://www.quirkster.com/iano/js/befunge.html).
**Explanation:**
A common year is *365 = 1 mod 7* days, so the year plus every 4th year, minus every 100th (`d` in ascii) year, plus every 400th years accounts for any leap days (including the present year). The result of `:::4"d"*/\"d"/-\4/++` can then be thought of as March 5th, the first day after February to fall on the same day as the first day of the year in common years. After that we calibrate to the pattern with `5+7%-` subtracting a number of days of the week from the 28th(the `47*`stored earlier) of November. Then print.
A version correcting for B.C. years is currently longer than the bonus provides for, at 59 -25% = 44.25 bytes:
```
47*&v
!`0:<+*"(F"_v#
" voN",,,,.@>:::4"d"*/\"d"/-\4/++5+7%-
```
[Answer]
## Matlab, 78 bytes
```
x=find(all(bsxfun(@eq,datestr(datenum(input(''),11,1:30),'ddd'),'Thu')'));x(4)
```
[Answer]
# Ruby, ~~60~~ ~~58~~ ~~42.75~~ 39 \* 0.75 = 29.25 bytes
```
->y{puts"Nov #{28-Time.new(y,9).wday}"}
```
**42.75 bytes**
```
->y{puts"Nov #{[5,4,3,2,1,7,6][Time.new(y,11).wday]+21}"}
```
**58 bytes**
```
->y{puts "Nov #{[5,4,3,2,1,7,6][Time.new(y,11).wday]+21}"}
```
**60 bytes**
```
->y{puts "Nov #{[5,4,3,2,1,7,6][Time.new(y,11,1).wday]+21}"}
```
Ungolfed:
```
-> y {
  puts "Nov #{[5,4,3,2,1,7,6][Time.new(y,11).wday]+21}"
}
```
Tests:
```
->y{puts"Nov #{28-Time.new(y,9).wday}"}.(2015)
Nov 26
->y{puts"Nov #{28-Time.new(y,9).wday}"}.(1917)
Nov 22
->y{puts"Nov #{28-Time.new(y,9).wday}"}.(-480)
Nov 25
```
[Answer]
# PHP 5.3+, 59 bytes
This uses PHP builtin function [`strtotime`](http://php.net/manual/en/function.strtotime.php) to parse the date.
```
<?=gmdate('M d',strtotime("Next Thursday $_GET[Y]-11-19"));
```
This expects the value to be passed over GET parameter `Y` **OR** over `php-cli Y=<year>`.
It tries to find the next thursday after 19th November.  
So far, with the tests I've made, it works fine.
Be aware that 2-digit years may be interpreted differently.
I use `gmdate` to avoid timezone issues, but it works equally well using `date` (at least, where I live).
[Answer]
# GNU coreutils, 35 bytes
```
seq -f$1-11-2%g 2 8|date -f-|grep h
```
Simply searches the week 22-28 November for a Thursday. Run it in a C or POSIX locale, as I depend on Thursday being the only day abbreviation to contain a 'h'.
---
Here's a cleverer answer, albeit a byte longer:
```
echo Nov $((28-`date -d$1-5-5 +%w`))
```
We retrieve the day-of-week number of a date in a fairly arbitrary week between March and September (so day and month are one digit each, and we're not affected by a possible leap day). We pick the day so that it's a Sunday (`%w==0`) when Thanksgiving is on the 28th. We can then subtract that value from 28 to obtain the appropriate Thursday.
[Answer]
# VBA, 124 bytes \* 75% = 93 bytes
```
Function e(y)
For i = 1 To 7
x = DateSerial(y, 11, 21) + i
If Weekday(x) = 5 Then e = Format(x, "mmm dd")
Next
End Function
```
I'm not sure if spaces count, it's somewhere between 102 and 124, feel free to edit.  
If integers are a valid output I'm more than happy to remove the `Format` part.
[Answer]
# T-SQL ~~215 bytes~~ 248 \* 0.75 = 186 bytes
```
create function t(@y int)returns table return select x=convert(char(6),x,107)from(select x=cast(dateadd(dd,d,dateadd(yy,@y-2015+7600,'20151101'))as date)from(select d=21+n from(values(0),(1),(2),(3),(4),(5),(6))b(n))c)t where datepart(weekday,x)=5
```
Ungolfed
```
set nocount on;
if object_id('dbo.t') is not null drop function dbo.t
go
create function t(@y int)returns table return
    select x=convert(char(6),x,107)
    from (
        select
        x=cast(dateadd(dd,d,dateadd(yy,@y-2015+7600,'20151101'))as date)
        from (
            select d=21+n 
            from (values (0),(1),(2),(3),(4),(5),(6))b(n)
        )c
    )t
    where datepart(weekday,x)=5
go
```
which with this test scaffold
```
select 
  [ 2015 = Nov. 26]=(select x from dbo.t( 2015))
 ,[ 1917 = Nov. 22]=(select x from dbo.t( 1917))
 ,[ 1752 = Nov. 23]=(select x from dbo.t( 1752))
 ,[ 1582 = Nov. 25]=(select x from dbo.t( 1582))
 ,[ 1400 = Nov. 27]=(select x from dbo.t( 1400))
 ,[ -480 = Nov. 25]=(select x from dbo.t( -480))
 ,[-5480 = Nov. 28]=(select x from dbo.t(-5480))
;
go
```
yields as desired
```
2015 = Nov. 26  1917 = Nov. 22  1752 = Nov. 23  1582 = Nov. 25  1400 = Nov. 27  -480 = Nov. 25 -5480 = Nov. 28
--------------- --------------- --------------- --------------- --------------- --------------- ---------------
Nov 26          Nov 22          Nov 23          Nov 25          Nov 27          Nov 25          Nov 28
```
[Answer]
# [Pike](http://pike.lysator.liu.se), ~~87 91 107 77~~ 76 bytes - 25% = 57
```
string t(int y){return"Nov "+((11-Calendar.Day(y,11,1)->week_day())%7+22);}
```
leaving the old one in for comparison because i find it more clever in terms of taking advantage of the Calendar module, but the above is way shorter.
```
string t(int y){object n=Calendar.Month(y,11);return"Nov "+(n->weeks()->day(4)&n->days())[3]->month_day();}
```
[Answer]
## [Smalltalk - Squeak and Pharo](http://beginningtosmalltalk.blogspot.com), ~~69~~ ~~57~~ ~~54~~ ~~49~~ ~~35~~ ~~34~~ ~~33~~ 32 - 25% = 24 bytes
**"Nov nn": ~~69B~~ 49B (-25% = 36.75B)**  
**11nn (anInt): ~~57~~ ~~54~~ 32B (-25% = 24B)** 
```
"Year supplied as an integer value, y  
 Result provided as an integer value, 11nn
 Methods Date>>y:m:d: and >>w created as duplicates 
 of year:month:day and weekdayIndex"
(12-(Date y:y m:11d:1)w)\\7+1122
```
Previous versions 
**11nn output**
```
"Year supplied as an integer value, y  
 Result provided as an integer value, 11nn"
(12-(Date year:y month:11 day:1) weekdayIndex)\\7+1122
"Year supplied as an integer value, y  
 Result provided as an integer value, d, prefixed by 11"
d:=(12-(Date year:y month:11 day:1) weekdayIndex)\\7+1122
```
**Nov nn output**
```
"Year supplied as an integer value, y  Result provided as a string, 'Nov nn'"
'Nov ', (12-(Date year:y month:11 day:1) weekdayIndex\\7+22) asString
```
**nn output**
```
"Year supplied as an integer value, y  Result provided as an integer value, d"
d:=(12-(Date year:y month:11 day:1) weekdayIndex)\\7+22
```
n.b. This is provided as a program - specifically a Workspace expression - rather than as a method. 
It assumes the input is a given (as per the phrasing "given an up-to-four-digit year".  
Including the declaring and giving of the input would add another 11 characters:
`|y|y:=2015.(12-(Date y:y m:11 d:1)w)\\7+1122`
Thanks to eMBee, for showing how to remove yet one more char - the whitespace immediately before the 'w'.
Actually, that inspired me to try removing the whitespace before 'd:' :  
`|y|y:=2015.(12-(Date y:y m:11d:1)w)\\7+1122`  
Which worked!
[Answer]
# TSQL, ~~53~~ 52 bytes
```
DECLARE @ CHAR(4)=2000
PRINT DATEADD(d,59,DATEDIFF(d,1,DATEADD(m,9,@))/7*7)
```
**[Fiddle](https://data.stackexchange.com/stackoverflow/query/508977/when-is-thanksgiving)**
Calculating monday before or on september 2nd and adding 59 days
(better than calculating monday before or on october 4th and adding 31 days because october is the 10th month thus saving 1 byte)
[Answer]
## Perl, 92 bytes
```
use Time::Local;(localtime(timelocal 0,0,0,$_,10,$ARGV[0]))[6]==4?print "Nov $_":0for 22..28
```
EDIT : Fixed output format, fixed bug e.g. 2012 result, used shorter "for" format. Thanks to msh210.
]